@iguano - I dont know, if you are on telegram/discord group, but I welcome you.
Thanks! I'm gonna check out the discord group sometime soon.
What's interesting for us is the calculation of PoS block trust:
CBigNum bnNewTrust = (CBigNum(1)<<256) / (bnTarget + 1);
This line is called every time when a PoS block is detected. It sets the "block trust" for PoS blocks basically to a value correlated directly with PoW difficulty. The higher the difficulty, the higher the "trust" of the block.
After that line, there are some mechanisms in place meant to ensure that there are not too many PoS blocks in a row. So the block trust is reduced to a third if:
- the parent block of the PoS block is not a PoW block
- there are less than 3 PoW blocks in the last 12 PoS blocks
If both conditions are met, chain trust gets reduced to 1/9 of the value of the first PoW block in the row.
Interesting observation... but that last sentence is not quite correct. The two reductions will not be combined to 1/9 because the
bnNewTrust/3 is returned right away. This kind of makes this problem more serious because PoS blocks will typically have 1/3 the trust of a PoW block.
I don't know if setting trust values to zero would be the best solution to this. Someone who can dominate PoS and is capable of producing at least a single PoW block could just prepare a long chain of PoS block and then mine a PoW block on top of it. Since the PoW block has nonzero trust, the network should accept it regardless of how many PoS blocks there are (unless I'm missing something). I think it would be more clean to just put a hard cap on the number of consecutive PoS blocks ("if the last N blocks were PoS and this block is PoS too, reject it"). This should be doable in a soft fork.
I have looked at 5000 blocks starting at 1467845 and gathered some data:
PoS blocks make up two thirds of the total trust score and 80% of the total number of blocks.
PoW has 27.5% trust and 15.4% blocks
PoB has 5.8% trust and 4.8% blocks
The main reason for this is that the target spacings massively favor PoS over everything else:
int64 nTargetSpacing = fProofOfStake ? STAKE_TARGET_SPACING :
min(nTargetSpacingWorkMax, (int64) STAKE_TARGET_SPACING * (1 + pindexLast->nHeight - pindexPrev->nHeight));
This piece of code (function
GetNextTargetRequired in main.cpp) increases the PoW block spacing to 15 minutes if there are enough PoS blocks. (one PoW block per 10 PoS blocks)
For PoB, there is a target spacing of one block per 3 PoW blocks (see GetNextBurnTargetRequired in main.cpp)
This also explains why there were periods during which PoS was not dominating: There simply weren't enough coins being staked to make one minimum-difficulty block every 90 seconds so this PoW-difficulty-increase mechanism didn't kick in back then.
So, in order to decrease the influence of PoS on the network, it would probably make sense to decrease nTargetSpacingWorkMax from
10*STAKE_TARGET_SPACING (15min) to something more sane. Or we could get rid of the mechanism that increases the PoW target spacing based on the PoS interval entirely (equivalent to setting nTargetSpacingWorkMax to
1*STAKE_TARGET_SPACING) This would require a hard fork however.
P.S.: I'm gonna restart staking now but I'll do it more gently for now