Skip to content
Tomáš edited this page Sep 11, 2017 · 15 revisions

Gridcoin PoS kernel v8

Author: TomasBrod. With credits to the PeerCoin and BlackCoin developers.

This document describes internals, effects and design decisions of Gridcoin PoS kernel stakev8. This V8 kernel will be used in blocks version 8 and replaces the previous kernel, V3, which was used in in blocks version 7.

Versions 4-7 were skipped and the kernel was simply named after the block version in order to reduce the amount of separate version numbers needed.

The most notable effect is that magnitude does no longer affect your stake weight. Investors and BOINCers now have the same chances to mint a block. This drastic change was needed to eliminate an exploit. On the other hand a compensation for less rich BOINCers is already being designed.

Basics

To create a next block in chain, miner must find a valid proof of something for it. Gridcoin is a PoS coin so the permission to create a next block is derived from the coins they own. There is also PoW, where the permission is derived from useless computation work the miner has to do. (Tomas is talking here about PoW as in asic mining, ... DPoR is not useless)

A PoW is always useless work, it is a work done for the sole purpose of reserving/wasting computational resources just to prove that work was done. Running BOINC is not useless, the work has an actual results and benefits to science, it is not a PoW. We can call it BOINC or DPoR work. (except Bitcoin Utopia project)

First a data string (called kernel) is formed from the kernel components, then the kernel is hashed to obtain a proof hash, and then this proof hash is compared to the current difficulty target. Both proof hash and target are (big) numbers. The kernel forms a valid proof only if the proof hash is less than the difficulty target.

The idea of PoS is that you can't just iterate over some nonce trying endlessly, burning your cpu/gpu/asic power, until you find a valid kernel. In PoS, you can only try using different coins you have and the current time.

You can view it like a lottery. Buying tickets for PoW equals to using more cpu/gpu/asic computing power. Tickets for PoS are the coins you own.

Change list

What changed in stake weight calculation and why:

  • RSA_WEIGHT (and thus magnitude) was removed from the weight calculation.
    • multiplication issue
    • not checked when receiving

What changed in stake kernel and why:

  • removed RSA_WEIGHT was removed from kernel
    • iterable nonce
  • Explicitly mask timestamps with STAKE_TIMESTAMP_MASK
    • just to be sure
    • mask was enforced elsewhere in prior version
  • removed por_nonce
    • iterable nonce
  • added Stake Modifier
    • prevent precomputation

Other changes set to take effect with block version 8:

  • Increased decimal places for encoding interest and boinc reward into boincHash. This allows staking blocks with reward less or equal to 0.005 if the mintLimiter allows it. In testnet mintLimiter is close to zero, in prod it is currently about 2.5 (changes with difficulty).

New Components

Stake weight of Mature Unspent Transaction Output (MUTXO) is a linear function of only its value.

Stake kernel is composed out of the following items:

  • current Stake Modifier
    • a number composed of enthropy gathered from past blocks
    • anti-pre-computation
  • Masked timestamp of the block where transaction whose output is used in this kernel is from
    • identification of the UTXO
  • hash of the abovementioned transaction
    • identification of the UTXO
  • output number of the kernel utxo
    • identification of the UTXO
  • current masked timestamp
    • time-bound iterable
    • a value that makes the kernel change in controlled manner

Old Issues

Total defeat of PoS purpose

Originally reported in issue #345.

A proof-of-work nonce is included in the current stake kernel degrading the consensus algorithm to Proof of Work. I don't know how to stress this enough. Gridcoin currently is and will be until v8 takes over a Proof of Work coin.

RSA_WEIGHT could perhaps be used as a nonce too.

  • Block nNonce no longer contributes to stake kernel.
  • RSA_WEIGHT no nonger contributes to the stake kernel.

Multiplication issue

Also reported in issue #332.

In v7 blocks there is a boost to your stake weight called RSA_WEIGHT. This boost consists of your current magnitude as GRC and, if you qualify as a newbie, an additional newbie boost of 100000 GRC. RSA_WEIGHT:=block.RSAWeight+block.Magnitude

All non-reserved mature UTXOs are used for staking in one miner run. And the weight bonus is added every time. For each UTXO RSA_WEIGHT bonus is added. FOR EACH. Wallet weight is sum of all UTXO weights. SUM(something)+constant =/= SUM(something+constant).

Thus the stakeweight boost from magnitude and newbie is multiplied by the amount of UTXOs you have, which is wrong. So splitting coins into multiple UTXOs does help you stake more.

  • Magnitude no longer contributes to stake weight.

However we should work towards adding a new minting mechanism based on research-age. To give crunchers with low balance some chance. Something like staking with beacon keys weighted by research-age instead of coins. And only allow research-age block after, say 10 normal coin-stake blocks.

Unchecked newbie weight bonus

Originally reported in issue #345.

RSAWeight field (stored in boincHash in coinbase) is currently used to give new users boost in stake weight. However it is not verified that it is indeed a new user. By modifying the source code attacker could hugely increase his weight and stake multiple times a day. Only the MintLimiter prevents him from creating even more blocks.

  • RSAWeight no longer contributes to stake weight.
  • The magnitude exploit also mentioned in the issue, was fixed shortly after by Rob.

Precomputation

V3 kernel does not include the Stake Modifier. Without the modifier, attacker can create transactions which output will stake at desired time. In other words attacker can check whether a transaction output will stake in the future and create transactions specially to stake once they mature.

  • Stake Modifier now contributes to the stake kernel.

Tips and Tricks

  • The first ever V8 block may be difficult to stake. It can take even 10x more time than block before (30min). For the transition it would be better if some whales lock their wallets 15 blocks in advance and unlock them for the transition block.

  • If you have such high balance that you are limited in staking by that 16 hours coin maturity requirement, then split your coins to stake more often.

  • On the other hand, if you stake (mint a block! more than once in 16 hours, you can combine your coins to stake less often by sending all balance at once to yourself.

Comments from the PR

Note: what follows is just an information store. It should/will be reworded and moved in the respective section up.

I would like to fix the issue with 1) unchecked rsaweight, 2) magnitude weight multiplication issue and 3) proof of work nonce being included in pos kernel making this effectively a pow consensus coin.

I think I fixed the above issues by introducing a new stake kernel and bumping the block version to 8. I named this new kernel "V8 kernel". This new kernel does not consider rsa and magnitude weight for security reasons. Does not include nonce but include the Stake Modifier. See some recent github issues and wiki for explanation why rsa/mag weight is dangerous.

Plug proof-of-work exploit. Stake modifier is included without much understanding. Without the modifier, attacker can create transactions which output will stake at desired time. In other words attacker can check wheter transactionoutput will stake in the future and create transactions accordingly. Thus including modifier, even not completly researched, increases security.

  • Edit: I now understand how SatakeModifier works and think it is secure.
  • Note: Rsa or Magnitude weight not included due to multiplication issue.
  • Note: Payment age and magnitude restrictions not included as they are not important in my view and are too restrictive for honest users.

Vehemently rejected, locally generated, v7 blocks are expected as I didn't implement all of the checks in Miner and instead relying on main block checking. This should happen much less with higher difficulty.

Interest is encoded on only 2 decimal places in boincblock (in v7 blocks) and 0.0051 is rounded up to 0.01, that is why we can't stake less or equal to 0.005 interest even thought mint limiter is only 0.000010 (depends on diff). Interesting. The rounding is also applied when deserializing. So just increasing places won't work. Forking change necessary. Edit: This was fixed in block version v8 by increasing decimal places.

Side note: you can force it to re-process all blocks with new rules as if received, by renaming blk0001.dat to bootstrap.dat and deleting txleveldb folder. This process still takes time, but is faster than re-download.

If you want to test, delete txleveldb, rename blk0001.dat to bootstrap.dat, set your wallet nick-name and add the usual node. There is no superblock on that fork, to stake you must switch to investor mode. The node nick name (-org= option) is to identify the staker for easier debugging. Set it to something like your github nick and unique suffix for each node.

Test reports, fraction of blocks staked by nodes.

First test, two nodes with roughly same balance:

{
  "general" : {
  "blocks" : 1001,
  "first_height" : 288160,
  "last_height" : 289160,
  "time_span_hour" : 28.26666667
 },
 "orgs" : {
  "TomasBrod.Mg.A" : 0.41458541,
  "TomasBrod.Mg.C" : 0.39360639,
  "" : 0.19180819
}}

Node MgA got some research rewards that increased it's balance. I guess 41.5% to 39.4% is close enough and within the error margin.

Second test, 3 nodes, MgA with 59kGRC, MgC with 20k and MgD with 10k.

{ "general" : {
  "blocks" : 532,
  "first_height" : 290100,
  "last_height" : 290631,
  "time_span_hour" : 14.16000000
 },
 "orgs" : {
  "TomasBrod.Mg.A" : 0.69548872,
  "TomasBrod.MgC$20k" : 0.21052632,
  "TomasBrod.MgD$10k" : 0.09398496
}}

Here the error is sightly higher I am not sure what is the cause but I guess it is still acceptable. The percentages are supposed to be 66%, 22% and 11%.

The average block spacing over the entire testing fork was 98.8 seconds. There were on average 874.4 blocks per day, which is little lower than the 1k bpd target.

You can come and test yourself @denravonska and @Foggyx420. But I guess this is good enough.

The RSA PPD values are no longer used to calculate rewards. Yes, i would like to rename the field, but I don't know good name for it. I am for separate page with more details that is good idea. We need to decide what info to be displayed on overview. And I am not skilled with gui.

There are other reasons for splitting your coins. I was kind of looking at how fast can you stake a block. But once you staked, your coins need to mature again and are not available for staking or spending for a certain amount of time. So if you want to stake regularly or want to stake as many blocks as possible in a certain amount of time it might be better to split your coins.

post list

https://github.com/gridcoin/Gridcoin-Research/issues/345 https://github.com/gridcoin/Gridcoin-Research/issues/332 https://github.com/gridcoin/Gridcoin-Research/issues/313 https://github.com/gridcoin/Gridcoin-Research/issues/307#issuecomment-302317144

See also