Author

Topic: PPLNS (Read 63183 times)

newbie
Activity: 2
Merit: 0
June 27, 2019, 03:54:14 AM
#51
Thank you kano, appreciate your answer!

I am using Mendis terminology. His "score" is the "share diff" / "NW diff" - just wording stuff.

Good to hear a confirmation of how PPLNS is supposed to work - in the end quite simple Wink

--

I was going after his various enhancements which he updated in this OP.
There he indicates to have a solution for some extreme on the edge cases, where I try to get my head around.

So I should rephrase my final question - then would be - if I correctly implemented the "Mendi Rosenfeld Windowed PPLNS" method Smiley
I figured btw - payouts of his method are different - as PPLNS in your description always pays out the exact Blockreward.
Mendis method has  variance in there.

Thx & Cheers!
legendary
Activity: 4634
Merit: 1851
Linux since 1997 RedHat 4
June 26, 2019, 09:11:13 PM
#50
PPLNS has no scoring.

Each share has the same value per difficulty, you just add up the total difficulty of a miner's shares and divide it by the total difficulty of all the shares used for N to get their % of the total reward.
newbie
Activity: 2
Merit: 0
June 26, 2019, 04:37:43 AM
#49
Heya everyone,

thank you very much esp. Meni Rosenfeld for explaining the PPLNS method in great detail. Maybe someone here can shed a bit of light to a little detail:
I am trying to implement the scheme and therefor have consulted this thread and re-read it numerous times.
Also I have studied the source code of some open source pools. I am pretty much sure to have understood it, but have found different implementations, and am in doubt especially about to how to understand the boundary conditions.

My main question still is - how to treat the "last" (oldest) share - meaning the one which brings the Totalscore > X.

a) let r become negative and include this share into the payment.

b) stop 1 share before - at the "last" share where Totalscore <= X.

After studying a lot I came to the following conclusion (method b) and would like to sum up and show how my understanding is, in one post so to say. It maybe help others, and would like to ask for comments if everything is correct.

Therefor I prepared an example with 10 shares, and easy to calculate numbers.
The following mini spreadsheet visualizes what I mean:

https://pasteboard.co/IlbdR2U.png

Boiling everything down, it looks like a very simple pseudo code:

Code:
0. TotalScore = 0, X = 2, B = Block.Reward


1. Calculate score of Winning share:

s = Share Diff / NW Diff and remember as t


2. Do WHILE TotalScore < X
      
      s = share.Difficulty / network.Difficulty

      TotalScore += s

      r = X - TotalScore

      Payout = (s * B) / (t * X) * min(r, t)

      TotalPayout += Payout

      share.Next()

What do you say - is that a correct PPLNS implementation?

Thank you very much!

Randominer  Smiley
legendary
Activity: 4634
Merit: 1851
Linux since 1997 RedHat 4
January 06, 2015, 05:54:08 PM
#48
the cex io guys deffered me to this link when asked why im having negative balance for holding 1gH/s

Now you know what kind of people your dealing with...
... "what kind of people" a sizable % of the network (>10%?) of people are silly enough to deal with ...
It's actually quite astounding that so many people do, and even before when this was already obvious, that a much higher % were.
legendary
Activity: 1302
Merit: 1001
January 06, 2015, 03:43:00 PM
#47
the cex io guys deffered me to this link when asked why im having negative balance for holding 1gH/s

Now you know what kind of people your dealing with...
donator
Activity: 2058
Merit: 1054
January 06, 2015, 05:55:54 AM
#46
the cex io guys deffered me to this link when asked why im having negative balance for holding 1gH/s
And that's bullshit on cex's part. PPLNS is a pooled mining reward system which you cannot possibly have a negative balance. You have a negative balance for buying a rip off cloud mining service which gets its "income" from a pooled mining reward.
I agree.
-ck
legendary
Activity: 4088
Merit: 1631
Ruu \o/
January 06, 2015, 03:54:13 AM
#45
the cex io guys deffered me to this link when asked why im having negative balance for holding 1gH/s
And that's bullshit on cex's part. PPLNS is a pooled mining reward system which you cannot possibly have a negative balance. You have a negative balance for buying a rip off cloud mining service which gets its "income" from a pooled mining reward.
sr. member
Activity: 637
Merit: 262
January 06, 2015, 03:39:52 AM
#44
the cex io guys deffered me to this link when asked why im having negative balance for holding 1gH/s
donator
Activity: 2058
Merit: 1054
March 23, 2014, 07:20:55 AM
#43
The correct method is as follows.
1. Choose a parameter X, which represents multiples of D to include in the window when difficulty is static. X=2 is a good choice.
2. When a share is submitted, assign to it a score of 1/D, where D is the difficulty at the time the share is submitted.
3. When a block is found, pay (sB)/X for the last share (the one before the winning share), where s is the share's score and B is the block reward. Continue backwards, paying each share based on its score, until you reach a share which brings the total score of the shares counted above X. Pay that share the amount (sB)/(tX) * min (r,t), where r is the score required to bring the total to exactly X and t is the score of the winning share. Don't pay any older shares.
4. If the pool has just started, and a block is found before there are shares totaling a score of X, there will be leftover rewards and it should be decided what to do with them. It doesn't matter much, but I recommend that the operator keeps them (in a macroscopic view, if the pool ever changes, this is compensation for the funds needed to cash participants out). Other options include donating to charity, or distributing among the miners.
How does this (specifically steps 2 & 3) change when a pool fee is involved? Is B simply reduced by the fee amount (e.g. B is only 99% of what it otherwise was in a 1% fee pool)?
This will be applied when the payment is calculated. If the fee is f (e.g., 1% fee is f=0.01), the amount to pay for a share will be (1-f)*(sB)/(tX) * min (r,t).
newbie
Activity: 56
Merit: 0
March 22, 2014, 12:25:04 AM
#42
The correct method is as follows.
1. Choose a parameter X, which represents multiples of D to include in the window when difficulty is static. X=2 is a good choice.
2. When a share is submitted, assign to it a score of 1/D, where D is the difficulty at the time the share is submitted.
3. When a block is found, pay (sB)/X for the last share (the one before the winning share), where s is the share's score and B is the block reward. Continue backwards, paying each share based on its score, until you reach a share which brings the total score of the shares counted above X. Pay that share the amount (sB)/(tX) * min (r,t), where r is the score required to bring the total to exactly X and t is the score of the winning share. Don't pay any older shares.
4. If the pool has just started, and a block is found before there are shares totaling a score of X, there will be leftover rewards and it should be decided what to do with them. It doesn't matter much, but I recommend that the operator keeps them (in a macroscopic view, if the pool ever changes, this is compensation for the funds needed to cash participants out). Other options include donating to charity, or distributing among the miners.

How does this (specifically steps 2 & 3) change when a pool fee is involved? Is B simply reduced by the fee amount (e.g. B is only 99% of what it otherwise was in a 1% fee pool)?
donator
Activity: 2058
Merit: 1054
March 07, 2014, 08:22:37 AM
#41
It doesn't help if N is chosen to be a given multiple of the difficulty at the time a block is found. If the difficulty is about to increase, it is more profitable to mine a short while before. For example, if N is set equal to the difficulty D, a share submitted D shares before the increase will be paid the full expectation in the D-window, and then when difficulty increased it will once again go inside the window and have more expected reward.

I am new to learning bitcoin mining, but I don't get your statement above: If N is set equal to D, then on average the window will just cover the round, so on average there will be no overlap.
That statement refers specifically to a change in difficulty at a roughly known future time. After the difficulty increases the retrospective window get larger, since it is a number of shares equal to the current difficulty.
newbie
Activity: 4
Merit: 0
March 06, 2014, 07:07:28 PM
#40
It doesn't help if N is chosen to be a given multiple of the difficulty at the time a block is found. If the difficulty is about to increase, it is more profitable to mine a short while before. For example, if N is set equal to the difficulty D, a share submitted D shares before the increase will be paid the full expectation in the D-window, and then when difficulty increased it will once again go inside the window and have more expected reward.

I am new to learning bitcoin mining, but I don't get your statement above: If N is set equal to D, then on average the window will just cover the round, so on average there will be no overlap.

member
Activity: 61
Merit: 10
August 08, 2013, 11:59:49 AM
#39
Works great, thanks!
donator
Activity: 2058
Merit: 1054
August 08, 2013, 01:44:59 AM
#38
Is it possible to calculate in advance how many shares will be included in the window? I'm thinking in terms of an implementation using a shares database (e.g., SQL). Before I begin collecting shares, can I compute approximately how many I will need to look at?
Yes, it will be approximately X * D. Depending on how you intend to use the approximation, a better one can be found.

My goal is to limit the number of rows fetched from the table to reduce server overhead. I would of course want to avoid the possibility of under-estimating, else the total payout wouldn't equal the block reward. Would I need to add anything to X*D to avoid underestimation?
If D1 is the current difficulty and D2 is the previous difficulty, an upper bound would be X * max (D1, D2) + 3. Taking the max makes sure that if the difficulty has just decreased, you won't miss the shares needed at the previously high difficulty; the +3 term helps with rounding, off-by-one errors etc., it can probably be tightened but it costs very little so I wouldn't bother.

Note that if the window spans more than one difficulty adjustment it may not work (you might need the maximum over previous difficulties as well) but that's not a situation I believe should happen.

If miners submit shares with difficulty greater than 1 this can be decreased. If d is the minimal difficulty that they can submit (assuming that throughout the window you only have shares with this difficulty or higher), and upper bound is X * max (D1, D2) / d + 3.
member
Activity: 61
Merit: 10
August 06, 2013, 02:29:14 PM
#37
Is it possible to calculate in advance how many shares will be included in the window? I'm thinking in terms of an implementation using a shares database (e.g., SQL). Before I begin collecting shares, can I compute approximately how many I will need to look at?
Yes, it will be approximately X * D. Depending on how you intend to use the approximation, a better one can be found.

My goal is to limit the number of rows fetched from the table to reduce server overhead. I would of course want to avoid the possibility of under-estimating, else the total payout wouldn't equal the block reward. Would I need to add anything to X*D to avoid underestimation?
donator
Activity: 2058
Merit: 1054
August 06, 2013, 02:10:36 PM
#36
Is it possible to calculate in advance how many shares will be included in the window? I'm thinking in terms of an implementation using a shares database (e.g., SQL). Before I begin collecting shares, can I compute approximately how many I will need to look at?
Yes, it will be approximately X * D. Depending on how you intend to use the approximation, a better one can be found.
member
Activity: 61
Merit: 10
August 06, 2013, 10:24:59 AM
#35
Is it possible to calculate in advance how many shares will be included in the window? I'm thinking in terms of an implementation using a shares database (e.g., SQL). Before I begin collecting shares, can I compute approximately how many I will need to look at?
donator
Activity: 2058
Merit: 1054
June 27, 2013, 06:37:23 AM
#34
I'm afraid I must make another correction to the OP: The payout (sB/tX) * min (r,t) is applied not just to the earliest share, but to all shares. For most shares r is much bigger than t so this reduces to sB/X, but there can be several early shares (not just the earliest) for which r
Thanks for the in-depth explanation.

After looking at this for over an hour, there is just 1 detail that I don't understand: For the final share (that only partially fits in the remainder of the window) how do we calculate the value of t?

Lets take the situation where a round has ended. (Network difficulty always = 240, block value always = 50, X=2, no pool fee)
The winning share is share number 28419 (which has share difficulty = 7).
Looking backwards from here, we begin paying out rewards with share number 28418 (which has share difficulty = 7).
....
We keep going until we get to a share that only partially fits in the remainder of the window: share number 28353 (which has share difficulty = 90).

When I calculate what I think is the value of t, the reward for the partial block ends up spilling well over the window boundary.
What would t be in this case?
(PS - This is actual data I have in a spreadsheet from a block mined on testnet)
t or r? t is simply the score of the winning share, 7/240 in this case.

For r, if all shares 28353-28418 are of difficulty 7, their total score is 66*7/240 = 1.925. Thus r = 0.075.

If you mean that the total payout is higher than the block reward, this is true. In this design, when small shares follow large shares the payout is bigger, when large shares follow small shares the payout is lower.

The practical difference is small since share scores aren't as big as 90/240 in reality.

Requiring that the payout is exactly equal to the block reward is not sustainable because the block reward is variable. However, if we assume the block reward is fixed, there are some alternative designs which satisfy this.

The "General unit-based framework" in AoBPMRS (currently section 5.2) does this, but isn't easy to implement. There's a randomized variant that is fairly easy though:

1. When a block is found, letting t be the score of the winning share, choose a random real u between 0 and t.

2. Pay out uB/X to the winning share.

3. Moving backwards, pay out sB/X to each share fully within the window, s being the share's score.

4. For the last (earliest) share, letting r be the score remaining to complete to X (where the winning share has contributed u), pay out rB/X.
newbie
Activity: 19
Merit: 0
June 26, 2013, 06:03:08 PM
#33
Thanks for the in-depth explanation.

After looking at this for over an hour, there is just 1 detail that I don't understand: For the final share (that only partially fits in the remainder of the window) how do we calculate the value of t?

Lets take the situation where a round has ended. (Network difficulty always = 240, block value always = 50, X=2, no pool fee)
The winning share is share number 28419 (which has share difficulty = 7).
Looking backwards from here, we begin paying out rewards with share number 28418 (which has share difficulty = 7).
....
We keep going until we get to a share that only partially fits in the remainder of the window: share number 28353 (which has share difficulty = 90).

When I calculate what I think is the value of t, the reward for the partial block ends up spilling well over the window boundary.
What would t be in this case?
(PS - This is actual data I have in a spreadsheet from a block mined on testnet)
donator
Activity: 2058
Merit: 1054
June 24, 2013, 05:36:13 PM
#32
Regarding the small correction you made, I don't quite understand what's happening.
Are we talking about the "oldest" share, the one that may get a partial reward (in order to get the total score to exactly X)?
If so, I don't see how "t" is relevant to the calculation, if "t" is the score of the "winning share" (i.e. the share that we didn't even take into consideration to begin with).
First we need to remember the goal; each share will have an expected reward of sB.

Thus we need to take a given share, and consider the rewards it will get from future shares.

We construct a timeline window of length X after the share and state that for every block found within this timeline, the original share will be rewarded by (sB/X). Since X blocks are expected to be found, the average reward will be sB.

More specifically, every future share found, with score t, will consume t units of the window, and will have probability t to result in a block giving a reward of sB/X, hence its expected reward is sBt/X. The invariant is that when t units are consumed, an expected reward of sBt/X is added. Thus, summing over shares totaling X units, the average reward is sB.

However, a problem remains with the last share in the window. It extends beyond the window, thus while its expected reward would be sBt/X, the amount of units it consumes is equal to the amount of units remaining in the window, which is r. To maintain the invariant, we modify the reward in case the last share is a block to sBr/tX (only a portion of r/t of the block, if found, is considered in the window). The expected reward would then be sBr/X, maintaining the invariant. This correction is only done for the last share in the window, which can be identified by the fact that r
This analysis took a share and looked at how much reward it needs to get from future shares if they end up a block; now we just need to look at it backwards to find out how much each block found needs to reward past shares. The result is what is in the OP.

My final question: Is X=2 an acceptable setting for real-world usage?
It depends on pool size and preference; for a smaller pool I'd say it's good, a larger pool could use a higher value (since maturity time becomes less of an issue).
newbie
Activity: 19
Merit: 0
June 24, 2013, 11:23:10 AM
#31
Thanks for that explanation.

Regarding the small correction you made, I don't quite understand what's happening.
Are we talking about the "oldest" share, the one that may get a partial reward (in order to get the total score to exactly X)?
If so, I don't see how "t" is relevant to the calculation, if "t" is the score of the "winning share" (i.e. the share that we didn't even take into consideration to begin with).

My final question: Is X=2 an acceptable setting for real-world usage?
donator
Activity: 2058
Merit: 1054
June 22, 2013, 02:10:50 PM
#30
I am currently implementing the "correct method" PPLNS and I have one question.

When a block is found, is the "winning share" counted in the window? (the original post suggests that it isn't)
If it isn't counted, what is the reasoning behind this?
Correct, it isn't.

If you included it, the expected payout for a share would depend on future difficulty changes. For example let X=1 and take an extreme case where after I submit a share, the difficulty changes to 1. Then the next share found will be a block and it will take the entire reward, and I will get nothing.

The same happens if instead of the global difficulty changing, a different share difficulty is submitted.

In practice the differences will be minor because shares are small. Where the difference between the naive method and the unit-based method is measured in percentage, the difference in how you count the edges is measured in ppm.

Actually, the question prompted me to revisit the model (it's been a while), and I noticed there was a small correction which I included in AoBPMRS but didn't fix in this post; for the last share, instead of a payout of (srB)/(tX), it should be (sB)/(tX) * min (r,t). I fixed it now.

PS. You should consider shift-PPLNS, I've specified the exact way to do it in this comment.
newbie
Activity: 19
Merit: 0
June 22, 2013, 02:12:59 AM
#29
I am currently implementing the "correct method" PPLNS and I have one question.

When a block is found, is the "winning share" counted in the window? (the original post suggests that it isn't)
If it isn't counted, what is the reasoning behind this?
donator
Activity: 2058
Merit: 1054
April 25, 2013, 10:52:31 AM
#28
PPLNS is "supposed to be" a method where there is no operator risk, he just pays out the rewards for each block in some way. However, for the method (or any other method) to be hopping-proof even when the block reward changes, this is no longer the case.

Shares are still paid (Bd / DX) duntil the total of d/D reaches X. If, when a block is found, the reward is low in comparison to the reward at the time recent shares were submitted, the amount he has to pay according to the method is higher than the block reward, and he must pay the difference from his own pocket. And conversely, if the actual block reward is higher he keeps the difference.


If B is highly variable it can cause quite a lot of risk to the operator. It could be mitigated by basing the credit per share not only on the expected contribution but also the variance created.


In pay-once PPLNS you know the maximum amount you can be paid for a share, but you don't know whether you'll be paid it at all or not. It's not just that you don't know when you'll get it. Future B has no effect on whether you get paid and when.
sr. member
Activity: 434
Merit: 250
April 24, 2013, 05:34:57 PM
#27
I added in a later comment that to be protected from hopping based on block reward (which will be critical when the reward is based on tx fees), B for each share needs to be chosen when the share is submitted, not when the block is found.

When a reward drop is coming up, like when Bitcoin went from 50 to 25, the shares submitted before the drop would be earning twice the reward as the shares after the drop if you store credit by current potential reward at the time of submission instead of the actual reward at the time a block is found. Is that that intentional? In a pure PPS model, that's how it'd have worked of course. But in a pay-once PPNLS model you can only pay back as many shares as you actually received from the found block. So if the D shares up to the reward drop didn't find a block, then D+1 finds a block with half the reward, you're only going to be able to pay the most recent D/2 shares. It seems a bit counter intuitive to me, I'd think the last D shares would all get paid on the actual block (half reward than if we found the block sooner, but it is what it is, you can only pay out what the pool receives).

I guess the same applies long-term with transaction fee based blocks, although then the reward would be going up and down from block to block.

For pay-once, does it just boil down to this then:

1- Knowing exactly what you are earning (share of potential reward+fees for current block, the reward you earned never changes between now and when you get paid) but not knowing how long until you get paid (if reward drops, your time until getting paid increases if your shares weren't recent enough)

OR

2- Knowing a better idea when you get paid (based on average time to solve blocks regardless of varying reward) but not knowing how much you'll earn (reward+transaction fees of the block actually found in the future).

As far as I understand things currently, most PPS models (should, if coded to use reward at time of share) fall under #1. Pay-Once-PPLNS using block rewards at time shares are submitted would also fall under #1. Proportional would fall under #2.
sr. member
Activity: 434
Merit: 250
April 24, 2013, 07:55:50 AM
#26
Ah okay, excellent. The initial pool I'm setting up is for TRC where the difficulty changes with each block. I store in my shares database d (user selected difficulty) and D (difficulty of the block you just submitted a share for) but do all of the payment logic based on sum(d/D for each share submitted individually, ie: D will vary over time) in LIFO (most recent) order. I mark shares if paid and then ignore them moving forward (stored for graphing and historical record).

The only thing I'm not doing is storing the reward based on B at the time you submit a share. I was only storing "You have earned sum(d/D) blocks" and then pay it out when a block is found based on the reward of the block found, not the reward at the time of submission. Which is exactly what you said not to do. I'll need to look at that.
donator
Activity: 2058
Merit: 1054
April 24, 2013, 03:23:32 AM
#25
If you want a simple hopping-proof method, PPLNS is it (not the pay-once variant), assuming it's implemented correctly.
Is there a hopping proof way to implement the pay-once variant? Assuming you store d/D as your score for shares submitted as you outline in original post (this is the way I store share data already).
To be clear, when I said pay-once isn't it, I meant it's not simple, not that it's not hopping-proof.

I think if you follow the original method, and just cap the payment for each share to (sB/X), skipping already paid shares, it will work fine and be protected from hopping based on both pool past and future difficulty changes. You'll need to keep for each share not only whether it was paid, but how much, so if it was partially paid, it can be paid more in future blocks.

I added in a later comment that to be protected from hopping based on block reward (which will be critical when the reward is based on tx fees), B for each share needs to be chosen when the share is submitted, not when the block is found.
sr. member
Activity: 434
Merit: 250
April 23, 2013, 05:26:56 PM
#24
If you want a simple hopping-proof method, PPLNS is it (not the pay-once variant), assuming it's implemented correctly.

Is there a hopping proof way to implement the pay-once variant? Assuming you store d/D as your score for shares submitted as you outline in original post (this is the way I store share data already).
donator
Activity: 2058
Merit: 1054
April 23, 2013, 03:42:26 PM
#23
I should probably force myself to go with DGM and be done with it. I just like the simplicity of CPPSRB.
If you want a simple hopping-proof method, PPLNS is it (not the pay-once variant), assuming it's implemented correctly. Or shift-PPLNS which is more scaleable.

Thank you for your time and for writing the Analysis paper.
You're welcome.
sr. member
Activity: 434
Merit: 250
April 23, 2013, 12:28:03 PM
#22
To be really wacky one could do pay-twice-PPLNS with X=2.

I should probably force myself to go with DGM and be done with it. I just like the simplicity of CPPSRB.

Thank you for your time and for writing the Analysis paper.
donator
Activity: 2058
Merit: 1054
April 23, 2013, 10:54:43 AM
#21
Not really. If for example X=0.5 then still normally a block will be paid out 100% to recent miners - each share will be paid twice the PPS rate. But in lucky times when there aren't enough unpaid shares, past miners can be paid.

An X < 1 will further increase the time to maturity on old shares, won't it? Is there a way in a pay-once-PPLNS model to avoid an unbounded time to maturity?
It's variance, not maturity time. A miner submitting a share has a chance to get more than the PPS amount, but also a chance to get nothing at all, ever. If he does get paid, it will be with high probability in a short time.
sr. member
Activity: 434
Merit: 250
April 23, 2013, 10:26:17 AM
#20
Not really. If for example X=0.5 then still normally a block will be paid out 100% to recent miners - each share will be paid twice the PPS rate. But in lucky times when there aren't enough unpaid shares, past miners can be paid.

An X < 1 will further increase the time to maturity on old shares, won't it? Is there a way in a pay-once-PPLNS model to avoid an unbounded time to maturity?
donator
Activity: 2058
Merit: 1054
April 23, 2013, 05:16:21 AM
#19
A substantially different variant is to pay for every share at most once. If, when going backwards in the list of shares, we encounter some that were already paid, we skip them and move on to older shares. X needs to be less than 1 to make sure that eventually we will have enough unpaid shares to draw on. I'm not sure what's the correct way to handle difficulty changes with this variant.
In effect, like a pool charging a 1% fee but paying that fee to past-due shares instead of it going to the operator?
Not really. If for example X=0.5 then still normally a block will be paid out 100% to recent miners - each share will be paid twice the PPS rate. But in lucky times when there aren't enough unpaid shares, past miners can be paid.

Payment always starts at the last share and continuously moves backward as much as possible, skipping any already paid shares.
legendary
Activity: 2576
Merit: 1186
April 22, 2013, 03:33:46 PM
#18
A substantially different variant is to pay for every share at most once. If, when going backwards in the list of shares, we encounter some that were already paid, we skip them and move on to older shares. X needs to be less than 1 to make sure that eventually we will have enough unpaid shares to draw on. I'm not sure what's the correct way to handle difficulty changes with this variant.

Is this in effect what CPPSRB does? It pays all shares only once, starting with the most recent and going back as far as needed to pay out the full block (or until every share is paid). Your % of the block reward is the sum of all of your d/D since last block, where the total shares we're paying is = block difficulty of the block we just found.
The difference I see, is that if CPPSRB pays off all shares, it saves the excess for the next block.
sr. member
Activity: 434
Merit: 250
April 22, 2013, 03:28:43 PM
#17
A substantially different variant is to pay for every share at most once. If, when going backwards in the list of shares, we encounter some that were already paid, we skip them and move on to older shares. X needs to be less than 1 to make sure that eventually we will have enough unpaid shares to draw on. I'm not sure what's the correct way to handle difficulty changes with this variant.

Is this in effect what CPPSRB does? It pays all shares only once, starting with the most recent and going back as far as needed to pay out the full block (or until every share is paid). Your % of the block reward is the sum of all of your d/D since last block, where the total shares we're paying is = block difficulty of the block we just found.

Your comment on X being less than 1 to avoid an endless backlog is what caught my attention. Is the way I should think of that, if X is .99 then miners are making 99% of the reward and 1% is being kept back to pay shares older than the miners normally being paid. In effect, like a pool charging a 1% fee but paying that fee to past-due shares instead of it going to the operator?
donator
Activity: 2058
Merit: 1054
February 25, 2012, 04:35:16 PM
#16
You need to distinguish score (which in some other places I call "units") from reward. Score is s=1/D and is the thing that should total X. (from the OP, "a score of 1/D... until you reach a share which brings the total score of the shares counted above X".) Reward is what you pay for each included share, and is s*B/X.

I hope there are some pieces to the computation you're not showing here, because some things are missing with respect to the accurate variant. In particular, you need D and B to be the values at the time the share was submitted rather than at the time payments are handed out (the OP clarifies this for D, but was written before I realized this is also true for B), and for absolute accuracy you need to proportionally discount the reward for the earliest share (the one that brings the total score to X).
sr. member
Activity: 403
Merit: 250
February 25, 2012, 04:18:15 PM
#15
Doing a bit of bumping right now, but i think it's appropriate.
We at Bitlc.net is changing from Propotional to PPLNS as soon as possible, but first I want to clarify something.

I'm struggling to understand your algorithm in the first post, i don't really get how X=2 results in payments for difficulty*2 (?)

This is my algorithm (in PHP), more or less:

Quote
$total = 0;
$N = 0;

$X = 2; // Magic number
$D = 1376302.267886; // Curr difficulty
$s = 1/$D; // Share score
$B = 50; // Block reward

$reward = ($s * $B) / $X; // per share

while($X > $total) {
        $N++; // Increment the share count, just to check how many shares that actually would be paid.
        $total = $total + $reward; // Total score
}

Results in:
$total = 2.0000148689956; // Total score
$N = 110105; // So 110105 shares was paid(?)

I've seen that people are using diff/2 (N = 688151 shares) and diff*2 (N = 2752604 shares)
What is it that i don't understand? Why does my code above results in N = 110105? :/

Thanks for any help that i can get.

--
Regards, Jim


EDIT: Oh crap, while writing this i just realized that i might have read wrong in the original post.
Each share is worth $s - NOT $reward ?

Please confirm if this is the case Smiley
donator
Activity: 2058
Merit: 1054
September 03, 2011, 01:07:24 PM
#14
I am currently considering this variation for my pool: PPLNS=Pay Per Last N Shifts
This is less resource-intensive than shiftless 0-1 PPLNS, but I don't find it simpler. I think exponential PPLNS is simplest in both presentation and resources (since you only need to keep track of one number per worker). For a full description of this, take the double geometric method with o=1. Note that for display purposes the relevant quantity is S/s.

I'd base shifts on a specified quantity of score. Suppose X=0.1, if a shift starts at D=1M, 50K shares are submitted, then D increases to 2M and 100K more shares are submitted, this completes a shift (50K/1M + 100K/2M = 0.1).

It's ok to change X between shifts and to base shifts on units of time, as long as you don't end shifts based on number of blocks found. Any block found in a shift of size X, gives a reward of (B*S)/(N*X) to any worker whose total score in the previous N shifts is S.

The idea is: If I submit a share, I get score p which qualifies me to an expected reward of pB. For each of the next N shifts, the expected number of blocks found is X (where X is specific to that shift), so if I'm rewarded (B*p)/(N*X) per block that's on average pB/N for any future shift, and since there are N the average reward is pB.
legendary
Activity: 2730
Merit: 1034
Needs more jiggawatts
September 02, 2011, 10:34:15 AM
#13
I am currently considering this variation for my pool: PPLNS=Pay Per Last N Shifts

D = difficulty
N = number of shifts eligible for payment
D2S = difficulty to shift ratio

Number of shares that go in a shift = D/D2S

Stored for each shift:
Number of shares for each user

When receiving any proof of work:
Increment the user's number of shares in the current shift
Unless the total number of shares in the shift exceeds D/D2S, in that case start a new shift and mark the old as completed

When receiving a generating proof of work:
For the last N completed shifts, weight=total_shares_in_shift
Distribute income proportionally among shifts according to their weight, and proportionally within shifts according to how many shares each user has.

As long as shifts are weighted, it might work out ok to pay for last N hours as well. Just start new shifts every hour instead of when the current shift reaches a certain size.

Benefits:
  • Fairly simple; easier to understand and to audit.
  • More transparent; easier to display all the data from which a user's payment was calculated.
  • Much lower storage and processing costs for server. Side-effect: easier to show live statistics and future payment estimates.

To avoid the time around difficulty changes from being hoppable it may be necessary to weight shifts also by their difficulty.

Any thoughts?
sr. member
Activity: 404
Merit: 250
September 01, 2011, 11:12:50 AM
#12
If there are 10 pools like this, can't I set them all up to be .1N a day in advance or whatever, mine for a bit at one, and then bump up the N and jump to the next .1N pool? Especially if you allow people to change their N at will, they can just make it float along so that their last batch of mined blocks is always in focus, until they drop it back to the minimum and begin mining again.
I'm not sure I understand what you mean, but I think you missed the point that you can configure what X will be for the future shares you submit to the pool, not for past shares. Although there's no problem with changing X for past shares, as long as they're rescaled to maintain the same expected payout.

You are right, I misunderstood. Thanks!
donator
Activity: 2058
Merit: 1054
September 01, 2011, 10:14:20 AM
#11
If there are 10 pools like this, can't I set them all up to be .1N a day in advance or whatever, mine for a bit at one, and then bump up the N and jump to the next .1N pool? Especially if you allow people to change their N at will, they can just make it float along so that their last batch of mined blocks is always in focus, until they drop it back to the minimum and begin mining again.
I'm not sure I understand what you mean, but I think you missed the point that you can configure what X will be for the future shares you submit to the pool, not for past shares. Although there's no problem with changing X for past shares, as long as they're rescaled to maintain the same expected payout.
sr. member
Activity: 404
Merit: 250
September 01, 2011, 05:48:14 AM
#10
Something that I'd be interested in and where I'd really love to know if it's possible:

Can you let your users choose N (in multiples of D) individually?

Let's say I have a miner that wants to have payouts as fast as possible and be able to cash out and leave the pool quickly at any time - so he chooses N = 0.5*D
Another one really loved the idea of prop that every share gets paid at least something and wants to be paid something at every (or nearly every) share, so he chooses N=10*D

Is it possible to pay these users their fair share without enabling them to hop the pool by creating a few workers witrh different Ns and choosing the optimal(?) one?

If there is a scoring system for this (and I suspect there is), users then could "tune" the pool payouts + variance to their individual needs. If you first had N=1 and then set it to N=10, of course you'd only apply this to shares submitted afterwards, not to past shares...
Yes, this is possible. It creates some variance for the operator, but if the pool's composition doesn't change much it's fairly small.

Basically, when you go backwards in the list of shares, you pay each share (sB/X) if the total score so far is less than X, where X is the value specific for this share. For participants it doesn't matter at all that others use a different X, because their own payments are exactly like in uniform PPLNS. For the operator it can matter, because there's no guarantee that the total paid is equal to the block reward, but long-term it will average out and I don't think the variance will be much of a problem.

This is consistent with some ideas I have for moving away from traditional reward systems and using a more general "futures market" for pool shares. Instead of distributing block rewards, the operator keeps block rewards but allows miners to trade shares for "bets" on blocks found in the future. This way there's no fundamental need for different miners to take the same bets. If the bets conform to one of the known reward systems, the system will reduce to them, and if the bets are offered in a way that the total obligation per block is equal to the block reward, you have 0 operator variance. And these contracts could be traded on an exchange, so investors who are not risk-averse and not mining themselves, can trade instant money for a contract that will have a higher eventual expected return. This will also allow miners to get cheap PPS. But I'm getting ahead of myself...

In the more immediate future, you can have a system where a miner can configure in the pool's website what reward system and parameters he wants to use, and get a quote for the fee the operator demands to compensate for the induced variance.

If there are 10 pools like this, can't I set them all up to be .1N a day in advance or whatever, mine for a bit at one, and then bump up the N and jump to the next .1N pool? Especially if you allow people to change their N at will, they can just make it float along so that their last batch of mined blocks is always in focus, until they drop it back to the minimum and begin mining again.
hero member
Activity: 658
Merit: 500
September 01, 2011, 02:31:35 AM
#9
you need to have a score system for PPLNS where each share is paid based on the current difficulty so when the difficulty changes the score for the new shares changes per share

so that way the rewards are consistent
and that means the round where the cutoff changes will have a weird amount of shares actually paid, in fact a single share could be partially paid to fairly reward the corrent N for the old difficulty and for the new difficulty
That's what I said in the OP. Are you simply agreeing with it?
this is the tl;dr version of your OP
donator
Activity: 2058
Merit: 1054
August 31, 2011, 01:09:40 AM
#8
you need to have a score system for PPLNS where each share is paid based on the current difficulty so when the difficulty changes the score for the new shares changes per share

so that way the rewards are consistent
and that means the round where the cutoff changes will have a weird amount of shares actually paid, in fact a single share could be partially paid to fairly reward the corrent N for the old difficulty and for the new difficulty
That's what I said in the OP. Are you simply agreeing with it?
hero member
Activity: 658
Merit: 500
August 30, 2011, 07:29:54 PM
#7
you need to have a score system for PPLNS where each share is paid based on the current difficulty so when the difficulty changes the score for the new shares changes per share

so that way the rewards are consistent
and that means the round where the cutoff changes will have a weird amount of shares actually paid, in fact a single share could be partially paid to fairly reward the corrent N for the old difficulty and for the new difficulty
donator
Activity: 2058
Merit: 1054
August 30, 2011, 02:20:18 AM
#6
Allowing users to change the N value themselves is a terrible idea for pool operators. Anyone implementing this please let me know though Cheesy
It won't be too bad if some limitations are imposed, e.g. X must be between 0.1 and 10, and can be changed only once per day. I want to say "and only after the account has already submitted some number of shares", but that may be too inconvenient for honest newcomers.

However, if implemented incorrectly, it is possible to hop based on imminent difficulty changes.

I wonder what the real world implications of this are - roughly: A 10 GH/s user that has an expected reward of 10 BTC can get an extra 0.2 BTC based on the difficulty decreasing 2% ?
Basically yes. If N is a fixed number of shares, D1 is the current difficulty, D2 is the future difficulty, p1=1/D1 and p2=1/D2, then the expectation for a share submitted just before the difficulty change is p2B where the fair reward is p1B, an increase by a factor of D1/D2. For a share submitted N shares before the difficulty change, the fair reward p1B is obtained. For the in-between period it increases linearly from p1B to p2B, so the total extra that could be obtained (with enough hashrate) is (p2-p1)NB/2 per difficulty change. Of course, to exploit it will require a reasonably accurate estimate of the time of difficulty adjustment, which is easier to do if the hashrate of the pool (including hoppers) is small.
c_k
donator
Activity: 242
Merit: 100
August 30, 2011, 12:10:39 AM
#5
However, if implemented incorrectly, it is possible to hop based on imminent difficulty changes.

I wonder what the real world implications of this are - roughly: A 10 GH/s user that has an expected reward of 10 BTC can get an extra 0.2 BTC based on the difficulty decreasing 2% ?
newbie
Activity: 40
Merit: 0
August 29, 2011, 11:33:23 PM
#4
Allowing users to change the N value themselves is a terrible idea for pool operators. Anyone implementing this please let me know though Cheesy
donator
Activity: 2058
Merit: 1054
August 29, 2011, 07:05:29 AM
#3
Something that I'd be interested in and where I'd really love to know if it's possible:

Can you let your users choose N (in multiples of D) individually?

Let's say I have a miner that wants to have payouts as fast as possible and be able to cash out and leave the pool quickly at any time - so he chooses N = 0.5*D
Another one really loved the idea of prop that every share gets paid at least something and wants to be paid something at every (or nearly every) share, so he chooses N=10*D

Is it possible to pay these users their fair share without enabling them to hop the pool by creating a few workers witrh different Ns and choosing the optimal(?) one?

If there is a scoring system for this (and I suspect there is), users then could "tune" the pool payouts + variance to their individual needs. If you first had N=1 and then set it to N=10, of course you'd only apply this to shares submitted afterwards, not to past shares...
Yes, this is possible. It creates some variance for the operator, but if the pool's composition doesn't change much it's fairly small.

Basically, when you go backwards in the list of shares, you pay each share (sB/X) if the total score so far is less than X, where X is the value specific for this share. For participants it doesn't matter at all that others use a different X, because their own payments are exactly like in uniform PPLNS. For the operator it can matter, because there's no guarantee that the total paid is equal to the block reward, but long-term it will average out and I don't think the variance will be much of a problem.

This is consistent with some ideas I have for moving away from traditional reward systems and using a more general "futures market" for pool shares. Instead of distributing block rewards, the operator keeps block rewards but allows miners to trade shares for "bets" on blocks found in the future. This way there's no fundamental need for different miners to take the same bets. If the bets conform to one of the known reward systems, the system will reduce to them, and if the bets are offered in a way that the total obligation per block is equal to the block reward, you have 0 operator variance. And these contracts could be traded on an exchange, so investors who are not risk-averse and not mining themselves, can trade instant money for a contract that will have a higher eventual expected return. This will also allow miners to get cheap PPS. But I'm getting ahead of myself...

In the more immediate future, you can have a system where a miner can configure in the pool's website what reward system and parameters he wants to use, and get a quote for the fee the operator demands to compensate for the induced variance.
legendary
Activity: 2618
Merit: 1007
August 29, 2011, 06:20:08 AM
#2
Something that I'd be interested in and where I'd really love to know if it's possible:

Can you let your users choose N (in multiples of D) individually?

Let's say I have a miner that wants to have payouts as fast as possible and be able to cash out and leave the pool quickly at any time - so he chooses N = 0.5*D
Another one really loved the idea of prop that every share gets paid at least something and wants to be paid something at every (or nearly every) share, so he chooses N=10*D

Is it possible to pay these users their fair share without enabling them to hop the pool by creating a few workers witrh different Ns and choosing the optimal(?) one?

If there is a scoring system for this (and I suspect there is), users then could "tune" the pool payouts + variance to their individual needs. If you first had N=1 and then set it to N=10, of course you'd only apply this to shares submitted afterwards, not to past shares...
donator
Activity: 2058
Merit: 1054
August 28, 2011, 07:04:16 AM
#1
PPLNS, or "Pay per last N shares", is a reward system that has been known for a while, but I don't think there's a definitive thread discussing it, including how to implement it in a way that is hopping-proof even considering difficulty changes.

The basic method is this: Whenever a block is found, payment is given to shares in a window, starting with the last share submitted and going backwards up to some number N of shares. Shares older than the window are not paid. This is essentially a 0-1 cutoff decay function. There is no concept of rounds - shares can be paid even if they were found before the previous block. This means that a given share can be paid more than once - however, the payouts are chosen so that the expected reward is equal to solo expected reward. Because the payment for a share depends only on blocks found in the future and not on shares and blocks found in the past, there is no way to hop based on the current status of the pool. However, if implemented incorrectly, it is possible to hop based on imminent difficulty changes.

The most naive implementation is to have a fixed N and simply pay the last N shares equally. However, this makes it more profitable to mine before difficulty decreases, and less profitable before difficulty increases - the number of blocks that are expected to be found in your window depends on the future difficulty, while the payout you can receive elsewhere depends on the current difficulty.

It doesn't help if N is chosen to be a given multiple of the difficulty at the time a block is found. If the difficulty is about to increase, it is more profitable to mine a short while before. For example, if N is set equal to the difficulty D, a share submitted D shares before the increase will be paid the full expectation in the D-window, and then when difficulty increased it will once again go inside the window and have more expected reward. And, like the previous case, shares submitted just before the difficulty change will be rewarded similarly to shares submitted after it.

Another incorrect implementation is to pay all shares in a window given in units of time (sometimes called PPLNM or PPLNH). In addition to the problems above, it has a problem common to all reward systems that use time as a factor, which is that it is more profitable to mine when the current hashrate is higher than the average.

The correct method is as follows.
1. Choose a parameter X, which represents multiples of D to include in the window when difficulty is static. X=2 is a good choice.
2. When a share is submitted, assign to it a score of 1/D, where D is the difficulty at the time the share is submitted.
3. When a block is found, pay (sB)/X for the last share (the one before the winning share), where s is the share's score and B is the block reward. Continue backwards, paying each share based on its score, until you reach a share which brings the total score of the shares counted above X. Pay that share the amount (sB)/(tX) * min (r,t), where r is the score required to bring the total to exactly X and t is the score of the winning share. Don't pay any older shares.
4. If the pool has just started, and a block is found before there are shares totaling a score of X, there will be leftover rewards and it should be decided what to do with them. It doesn't matter much, but I recommend that the operator keeps them (in a macroscopic view, if the pool ever changes, this is compensation for the funds needed to cash participants out). Other options include donating to charity, or distributing among the miners.

The expected payout for a share with score s, so that the total score of it and all younger shares is Y, is sB * Max (0, 1-Y/X). It follows that the expected payout per share when it is submitted is always B/D.

The variance in the payout per share is (pB)^2/X. The average number of shares it takes to receive payment, in multiples of the difficulty, is X/2. Thus X can be chosen to have the desired tradeoff between variance and maturity time, with the invariant being that their product is (1/2)*(pB)^2. Note that for a miner who constitutes a significant portion of the pool, the shares are correlated - if the portion is q, the total steady-state variance can't be lower than q times solo variance.

If the parameter X ever needs to be changed (for example, to harness increases in the pool's size to decrease variance without changing maturity in units of time), the scores of all recent shares should be changed so that their new expected remaining payout will be equal to the old one, starting from the youngest share and moving backwards. If X is increased, scores should be decreased. This creates a situation similar to the start of the pool where there could be leftover rewards. If X is decreased, scores should be increased. For some of the older shares, it will be impossible to increase the score to maintain the expected value. In this case they should be "cashed out", with the operator paying from his own funds their expected reward.

A variant of this is, instead of using a 0-1 cutoff, use an exponential decay function. This is equivalent to the double geometric method with o=1. If shares decay by a factor of e every (XD/2) shares, the variance is (pB)^2/X and the maturity time is X/2, just like with 0-1. The advantage is that the due payment of a miner can be encoded with a single number, his score - there's no need to keep or handle a history of shares. The disadvantages are that it takes longer to receive the reward in full, and that the implementation requires either a logarithmic scale or periodic rescaling.

Another variant is to use a linear decay function. This achieves a better variance-maturity tradeoff invariant, (4/9)*(pB)^2. However, it is probably harder to implement and understand.

A substantially different variant is to pay for every share at most once. If, when going backwards in the list of shares, we encounter some that were already paid, we skip them and move on to older shares. X needs to be less than 1 to make sure that eventually we will have enough unpaid shares to draw on. I'm not sure what's the correct way to handle difficulty changes with this variant.

Edit: Fixed an error in the description of the block payment.
Jump to: