Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.0 GAS distribution and rounding effects #2364

Closed
roman-khimov opened this issue Feb 25, 2021 · 2 comments
Closed

3.0 GAS distribution and rounding effects #2364

roman-khimov opened this issue Feb 25, 2021 · 2 comments

Comments

@roman-khimov
Copy link
Contributor

roman-khimov commented Feb 25, 2021

Describe the bug
In #1617 it was noted that 3.0 GAS distribution scheme loses direct correspondence of 1 NEO to 10⁻⁸ GAS distributed per block and in #1848 some (unavoidable) rounding errors were noticed. So I've decided to take a closer look at these issues and they're quite visible, so it's worth at least discussing them.

To Reproduce

  1. Create a chain (6 committee members with 4 validators in my case, that's the standard neo-go unit test chain)
  2. Create some ValidatorsCount number of "whale" accounts and transfer 10M of NEO to each of them
  3. Create "sender" account and transfer some 20M GAS generated in the genesis block (the amount should be sufficient to pay for all transactions, technically validators multisig account could be used, but this account simplifies signing)
  4. Register standby validators (4 in my case) as candidates
  5. Vote for them with "whale" accounts (1 account per one validator)
  6. Create a number of test accounts (each will be flipping its NEO with an interval of its own) and transfer some (1/5/10/...) amount of NEO to them, in the same block make some accounts vote for the first validator
  7. Now start generating blocks and add transactions flipping NEO (sending to itself) on test accounts, these transactions should be sent by the "sender" account, so that it spends GAS on fees while test accounts are only receiving it, and each account has its own block interval between transactions (1, 2, 3, 4, 5, 10, 100, 1000, 3000 in my case)
  8. Get GAS balance for each account after some number of blocks (3001 in my case)

Expected behavior

  1. Receive equal amount of GAS on different accounts irrespective of how often GAS is distributed
  2. Voters receive 9 times more GAS than non-voters (10% vs 80%)
  3. Increasing amount of voter/holder NEO increase the amount of generated GAS linearly

Real behavior
These are the results for owners of 1/5/10/100/.../1M NEO, the first column is the block interval between NEO transfers (1 is transferring each block), the second is amount of GAS generated on voter account and the third is amount of GAS generated on holder (non-voter) account.

1 NEO:
1        23500   0
2        25000   1500
3        24500   1000
4        25000   1500
5        24700   1200
10       25200   1500
100      25470   1500
1000     25497   1500
3000     25499   1500

5 NEO:
1        125502          6002
2        127002          7502
3        126502          7002
4        127002          7502
5        126702          7202
10       127202          7502
100      127472          7502
1000     127499          7502
3000     127501          7502

10 NEO:
1        254505          15005
2        254505          15005
3        254505          15005
4        254505          15005
5        254505          15005
10       254705          15005
100      254975          15005
1000     255002          15005
3000     255002          15005

100 NEO:
1        2549550         150050
2        2549550         150050
3        2549550         150050
4        2549550         150050
5        2549550         150050
10       2549750         150050
100      2549820         150050
1000     2549832         150050
3000     2549834         150050

1000 NEO:
1        25478500        1500500
2        25478500        1500500
3        25478500        1500500
4        25478500        1500500
5        25478500        1500500
10       25478700        1500500
100      25478910        1500500
1000     25478919        1500500
3000     25478919        1500500

10000 NEO:
1        252864000       15005000
2        252864000       15005000
3        252864000       15005000
4        252864000       15005000
5        252864000       15005000
10       252864200       15005000
100      252864260       15005000
1000     252864266       15005000
3000     252864266       15005000

100000 NEO:
1        2351884500      150050000
2        2351884500      150050000
3        2351884500      150050000
4        2351884500      150050000
5        2351884500      150050000
10       2351884700      150050000
100      2351884850      150050000
1000     2351884860      150050000
3000     2351884862      150050000

1000000 NEO:
1        14132078500     1500500000
2        14132078500     1500500000
3        14132078500     1500500000
4        14132078500     1500500000
5        14132078500     1500500000
10       14132078700     1500500000
100      14132078940     1500500000
1000     14132078943     1500500000
3000     14132078945     1500500000

1000000 NEO (additional, explained below):
1        19962038000     1500500000
2        21500500000     1500500000
3        21500500000     1500500000
4        21500500000     1500500000
5        19962038000     1500500000
10       21500500000     1500500000
100      21500500000     1500500000
1000     21500500000     1500500000
3000     19962038460     1500500000

Identified problems

  1. You can get exactly zero GAS for holding 1 NEO if you don't vote and transfer it with every block.
  2. If you make transfers more often you receive less GAS, the error is directly correlated to transfer frequency, big amounts of NEO hide that, although we're calculating just 3000 blocks here (half a day, roughly).
  3. Voting holders of big amounts of NEO actually receive less GAS per NEO and this "less" can be quite significant, voting with 1M NEO influences voterSumRewardPerNEO calculations and it seriously affects GAS distribution. Two results for 1M NEO are different in that in the chain for additional run holders of 1M NEO vote for different (i%ValidatorsCount) candidates while everywhere above votes are for the first validator.
  4. The problem above actually suggests that in real network with non-uniform vote distribution (this test chain is dominated by "whale" votes which are equal for each candidate) the amount of GAS received will be seriously affected by the number of votes for this candidate, the "additional" result proves this.
  5. Voters receive roughly 17 times more than non-voters, which suggests that GasPerBlock policy is not really respected at the moment, we can generate more than GasPerBlock GAS. Of course this only affects voters for validators, if you're to vote for ordinary committee member you'll receive 9 times more than non-voter (why would you though?).

(Optional) Additional context
This also is relevant for #2008 discussions because this PR makes GAS be distributed more frequently in general.

Committee incentive is specifically not touched here, it has some inevitable rounding errors too, but it's more stable and doesn't accumulate these errors.

@Qiao-Jin
Copy link
Contributor

This is because due to current distribution rule, distribution less than 1 gas factor is neglected.

@roman-khimov
Copy link
Contributor Author

Seeing this in real action on mainnet actually suggests that points 3-4 are features, not bugs, and point 5 is not entirely correct. The only problem is inevitable rounding (points 1-2), but while it makes the scheme not as perfect as the Legacy one was, it probably isn't really noticeable for regular users.

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

No branches or pull requests

2 participants