Quote from Meni Rosenfeld's post explaining PPLNS:

  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. 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.
  2. 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.
  3. 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.

So far so good. One thing I'm struggling to understand is where the difficulty of a share itself fits into the picture. How do I scale the reward by share difficulty without screwing up the algorithm?


What I also would like to know is how to handle cases where the network difficulty recorded with a share is different from the current network difficulty.

  • Re update: that is exactly what the post explains! You use the difficulty recorded with a share to compute its score. The "current" network difficulty (i.e. difficulty at the time the block is mined) never enters the computation at all. Jul 24 '17 at 18:56

Well, that post is quite old. Variable-difficulty shares weren't a thing then.

That said, I'm pretty sure the fix is as follows: When a share is submitted, the post says you should assign to it a score of 1/D. Instead, assign to it a score of d/D, where d is the share's difficulty. That's it.

Also, you should have a look at https://bitcoil.co.il/pool_analysis.pdf, specifically the "unit-PPLNS" part of section 3.3. It's slightly more complicated, but IIRC it has the advantage that it is still hopping-proof when the block reward can change (which is much more relevant now than it was back then).

As for changes in the network difficulty - the score is based on the historical difficulty, and the current difficulty is not used at all in the calculation.

If this seems odd, consider that if the current network difficulty is higher, than each new share has less chance to become a block and reward historical shares, but on the other hand, have a lower score and thus more shares are needed until the historical share is out of the window. So it evens out.


When a share of difficulty d > 1 is submitted, treat it as though d shares, each of difficulty 1, were submitted simultaneously.

  • So in essence the algorithm description assumes Diff1 shares and the calculated score must be multiplied by share-dificulty? Jul 24 '17 at 18:46
  • @OliverWeichhold: Well, it assumes all shares are of equal difficulty; that difficulty doesn't necessarily have to equal 1. You could have some "base difficulty" d0, and a share of higher difficulty d is treated as d/d0 base-difficulty shares. It wouldn't change anything. Jul 24 '17 at 18:54
  • Actually, while this gives a reasonable approximation, it's not as accurate and general as keeping it as one share but giving it a score of d/D instead of 1/D. Jul 24 '17 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.