mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
record total minted API v2 (#1769)
* feat: GetTokenSupply API, total minted and burned * feat: token supply API finish burned token. rename minted record functions * fix(api): handle edge case about minus 1 for epoch in token supply * fix: check both total minted and burned before breaking loop * style: modify minor style * style: modify by comment and rebase code * chore: modify test based on statedb_utils
This commit is contained in:
parent
c287f9eddd
commit
1089f0b4fe
5 changed files with 203 additions and 80 deletions
|
|
@ -144,21 +144,22 @@ func TestHookRewardV2SplitReward(t *testing.T) {
|
||||||
assert.Equal(t, 2, len(result))
|
assert.Equal(t, 2, len(result))
|
||||||
// two signing account, 3 txs, reward is split by 1:2 (total reward is 250...000)
|
// two signing account, 3 txs, reward is split by 1:2 (total reward is 250...000)
|
||||||
for addr, x := range result {
|
for addr, x := range result {
|
||||||
if addr == acc1Addr {
|
switch addr {
|
||||||
|
case acc1Addr:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("149999999999999999999", 10)
|
a, _ := big.NewInt(0).SetString("149999999999999999999", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]))
|
assert.Zero(t, a.Cmp(r[owner]))
|
||||||
b, _ := big.NewInt(0).SetString("16666666666666666666", 10)
|
b, _ := big.NewInt(0).SetString("16666666666666666666", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]))
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]))
|
||||||
} else if addr == signer {
|
case signer:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("74999999999999999999", 10)
|
a, _ := big.NewInt(0).SetString("74999999999999999999", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]))
|
assert.Zero(t, a.Cmp(r[owner]))
|
||||||
b, _ := big.NewInt(0).SetString("8333333333333333333", 10)
|
b, _ := big.NewInt(0).SetString("8333333333333333333", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]))
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]))
|
||||||
} else {
|
default:
|
||||||
assert.Fail(t, "wrong reward")
|
assert.Fail(t, "wrong reward")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -226,21 +227,22 @@ func TestHookRewardAfterUpgrade(t *testing.T) {
|
||||||
assert.Equal(t, 2, len(result))
|
assert.Equal(t, 2, len(result))
|
||||||
// two signing account, both get fixed reward
|
// two signing account, both get fixed reward
|
||||||
for addr, x := range result {
|
for addr, x := range result {
|
||||||
if addr == acc1Addr {
|
switch addr {
|
||||||
|
case acc1Addr:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("450000000000000000000", 10)
|
a, _ := big.NewInt(0).SetString("450000000000000000000", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
||||||
b, _ := big.NewInt(0).SetString("50000000000000000000", 10)
|
b, _ := big.NewInt(0).SetString("50000000000000000000", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
||||||
} else if addr == signer {
|
case signer:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("450000000000000000000", 10)
|
a, _ := big.NewInt(0).SetString("450000000000000000000", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
||||||
b, _ := big.NewInt(0).SetString("50000000000000000000", 10)
|
b, _ := big.NewInt(0).SetString("50000000000000000000", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
||||||
} else {
|
default:
|
||||||
assert.Fail(t, "wrong reward")
|
assert.Fail(t, "wrong reward")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,21 +267,22 @@ func TestHookRewardAfterUpgrade(t *testing.T) {
|
||||||
// 2 protector both get fixed reward
|
// 2 protector both get fixed reward
|
||||||
assert.Equal(t, 2, len(resultProtector))
|
assert.Equal(t, 2, len(resultProtector))
|
||||||
for addr, x := range resultProtector {
|
for addr, x := range resultProtector {
|
||||||
if addr == protector1Addr {
|
switch addr {
|
||||||
|
case protector1Addr:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("360000000000000000000", 10)
|
a, _ := big.NewInt(0).SetString("360000000000000000000", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
||||||
b, _ := big.NewInt(0).SetString("40000000000000000000", 10)
|
b, _ := big.NewInt(0).SetString("40000000000000000000", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
||||||
} else if addr == protector2Addr {
|
case protector2Addr:
|
||||||
r := x.(map[common.Address]*big.Int)
|
r := x.(map[common.Address]*big.Int)
|
||||||
owner := parentState.GetCandidateOwner(addr)
|
owner := parentState.GetCandidateOwner(addr)
|
||||||
a, _ := big.NewInt(0).SetString("360000000000000000000", 10)
|
a, _ := big.NewInt(0).SetString("360000000000000000000", 10)
|
||||||
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
assert.Zero(t, a.Cmp(r[owner]), "real reward is", r[owner])
|
||||||
b, _ := big.NewInt(0).SetString("40000000000000000000", 10)
|
b, _ := big.NewInt(0).SetString("40000000000000000000", 10)
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
||||||
} else {
|
default:
|
||||||
assert.Fail(t, "wrong reward")
|
assert.Fail(t, "wrong reward")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,11 +298,17 @@ func TestHookRewardAfterUpgrade(t *testing.T) {
|
||||||
b, _ := big.NewInt(0).SetString("30012500000000000000", 10) // this value tests the float64 reward
|
b, _ := big.NewInt(0).SetString("30012500000000000000", 10) // this value tests the float64 reward
|
||||||
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
assert.Zero(t, b.Cmp(r[config.XDPoS.FoudationWalletAddr]), "real reward is", r[config.XDPoS.FoudationWalletAddr])
|
||||||
}
|
}
|
||||||
totalMinted := statedb.GetTotalMinted().Big()
|
epochNum := uint64(3)
|
||||||
totalExpect, _ := big.NewInt(0).SetString("2100125000000000000000", 10)
|
totalMinted := statedb.GetPostMinted(epochNum).Big()
|
||||||
assert.Zero(t, totalMinted.Cmp(totalExpect), "statedb records wrong total minted")
|
expectMinted, _ := big.NewInt(0).SetString("2100125000000000000000", 10)
|
||||||
lastEpochNum := statedb.GetLastEpochNum().Big().Int64()
|
assert.Zero(t, totalMinted.Cmp(expectMinted), "statedb records wrong total minted")
|
||||||
assert.Equal(t, 3, int(lastEpochNum))
|
blockNum := statedb.GetPostRewardBlock(epochNum).Big().Int64()
|
||||||
|
assert.Equal(t, 2700, int(blockNum))
|
||||||
|
onsetBlock := statedb.GetMintedRecordOnsetBlock().Big().Int64()
|
||||||
|
assert.Equal(t, 2700, int(onsetBlock))
|
||||||
|
totalBurned := statedb.GetPostBurned(epochNum).Big().Int64()
|
||||||
|
// since no EIP 1559, so no burned
|
||||||
|
assert.Zero(t, totalBurned, "statedb records wrong total burned")
|
||||||
common.TIPUpgradeReward = backup
|
common.TIPUpgradeReward = backup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,9 +373,9 @@ func TestFinalizeAfterUpgrade(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// the recorded reward cannot be zero
|
// the recorded reward cannot be zero
|
||||||
minted := statedbAfterFinalize.GetTotalMinted()
|
epochNum := uint64(3)
|
||||||
|
minted := statedbAfterFinalize.GetPostMinted(epochNum)
|
||||||
assert.False(t, minted.IsZero())
|
assert.False(t, minted.IsZero())
|
||||||
t.Log("total minted", minted)
|
|
||||||
|
|
||||||
common.TIPUpgradeReward = backup
|
common.TIPUpgradeReward = backup
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,34 +152,62 @@ func (s *StateDB) GetVoterCap(candidate, voter common.Address) *big.Int {
|
||||||
return ret.Big()
|
return ret.Big()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
slotMintedRecordTotalMinted uint64 = 0
|
|
||||||
slotMintedRecordLastEpochNum uint64 = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *StateDB) GetTotalMinted() common.Hash {
|
|
||||||
hash := GetLocSimpleVariable(slotMintedRecordTotalMinted)
|
|
||||||
totalMinted := s.GetState(common.MintedRecordAddressBinary, hash)
|
|
||||||
return totalMinted
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StateDB) PutTotalMinted(value common.Hash) {
|
|
||||||
hash := GetLocSimpleVariable(slotMintedRecordTotalMinted)
|
|
||||||
s.SetState(common.MintedRecordAddressBinary, hash, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StateDB) GetLastEpochNum() common.Hash {
|
|
||||||
hash := GetLocSimpleVariable(slotMintedRecordLastEpochNum)
|
|
||||||
totalMinted := s.GetState(common.MintedRecordAddressBinary, hash)
|
|
||||||
return totalMinted
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StateDB) PutLastEpochNum(value common.Hash) {
|
|
||||||
hash := GetLocSimpleVariable(slotMintedRecordLastEpochNum)
|
|
||||||
s.SetState(common.MintedRecordAddressBinary, hash, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StateDB) IncrementMintedRecordNonce() {
|
func (s *StateDB) IncrementMintedRecordNonce() {
|
||||||
nonce := s.GetNonce(common.MintedRecordAddressBinary)
|
nonce := s.GetNonce(common.MintedRecordAddressBinary)
|
||||||
s.SetNonce(common.MintedRecordAddressBinary, nonce+1)
|
s.SetNonce(common.MintedRecordAddressBinary, nonce+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Storage slot locations (32-byte keys) within MintedRecord SMC
|
||||||
|
slotMintedRecordOnsetEpoch = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001")
|
||||||
|
slotMintedRecordOnsetBlock = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000002")
|
||||||
|
slotMintedRecordPostMintedBase, _ = new(big.Int).SetString("0x0100000000000000000000000000000000000000000000000000000000000000", 0)
|
||||||
|
slotMintedRecordPostBurnedBase, _ = new(big.Int).SetString("0x0200000000000000000000000000000000000000000000000000000000000000", 0)
|
||||||
|
slotMintedRecordPostRewardBlockBase, _ = new(big.Int).SetString("0x0300000000000000000000000000000000000000000000000000000000000000", 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *StateDB) GetMintedRecordOnsetEpoch() common.Hash {
|
||||||
|
return s.GetState(common.MintedRecordAddressBinary, slotMintedRecordOnsetEpoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) PutMintedRecordOnsetEpoch(value common.Hash) {
|
||||||
|
s.SetState(common.MintedRecordAddressBinary, slotMintedRecordOnsetEpoch, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetMintedRecordOnsetBlock() common.Hash {
|
||||||
|
return s.GetState(common.MintedRecordAddressBinary, slotMintedRecordOnsetBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) PutMintedRecordOnsetBlock(value common.Hash) {
|
||||||
|
s.SetState(common.MintedRecordAddressBinary, slotMintedRecordOnsetBlock, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetPostMinted(epoch uint64) common.Hash {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostMintedBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
return s.GetState(common.MintedRecordAddressBinary, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) PutPostMinted(epoch uint64, value common.Hash) {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostMintedBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
s.SetState(common.MintedRecordAddressBinary, hash, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetPostBurned(epoch uint64) common.Hash {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostBurnedBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
return s.GetState(common.MintedRecordAddressBinary, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) PutPostBurned(epoch uint64, value common.Hash) {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostBurnedBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
s.SetState(common.MintedRecordAddressBinary, hash, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) GetPostRewardBlock(epoch uint64) common.Hash {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostRewardBlockBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
return s.GetState(common.MintedRecordAddressBinary, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StateDB) PutPostRewardBlock(epoch uint64, value common.Hash) {
|
||||||
|
hash := common.BigToHash(new(big.Int).Add(slotMintedRecordPostRewardBlockBase, new(big.Int).SetUint64(epoch)))
|
||||||
|
s.SetState(common.MintedRecordAddressBinary, hash, value)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS"
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
"github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils"
|
||||||
|
|
@ -285,8 +286,8 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
currentConfig := chain.Config().XDPoS.V2.Config(uint64(round))
|
currentConfig := chain.Config().XDPoS.V2.Config(uint64(round))
|
||||||
// Get signers/signing tx count
|
// Get signers/signing tx count, and burned tokens in one epoch
|
||||||
signers, err := GetSigningTxCount(adaptor, chain, header, parentState, currentConfig)
|
signers, burnedInOneEpoch, err := GetSigningTxCount(adaptor, chain, header, parentState, currentConfig)
|
||||||
|
|
||||||
log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
log.Debug("Time Get Signers", "block", header.Number.Uint64(), "time", common.PrettyDuration(time.Since(start)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -361,24 +362,43 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
rewardsMap[rwt.key] = rewardResults
|
rewardsMap[rwt.key] = rewardResults
|
||||||
}
|
}
|
||||||
// record the total reward into state db
|
// record the total reward into state db
|
||||||
totalMinted := stateBlock.GetTotalMinted().Big()
|
totalMinted := new(big.Int)
|
||||||
lastEpochNum := stateBlock.GetLastEpochNum()
|
totalBurned := new(big.Int)
|
||||||
if lastEpochNum.IsZero() {
|
|
||||||
// if `lastEpochNum` is zero, the total minted has not included tokens before TIPUpgradeReward
|
nonce := stateBlock.GetNonce(common.MintedRecordAddressBinary)
|
||||||
// calculate the tokens before TIPUpgradeReward and set to totalMinted
|
if nonce == 0 {
|
||||||
// for now no-do
|
// initialize MintedRecordAddress
|
||||||
|
stateBlock.PutMintedRecordOnsetEpoch(common.Uint64ToHash(epochNum))
|
||||||
|
stateBlock.PutMintedRecordOnsetBlock(common.Uint64ToHash(number))
|
||||||
|
} else {
|
||||||
|
epochNumIter := epochNum
|
||||||
|
for epochNumIter > 0 {
|
||||||
|
epochNumIter--
|
||||||
|
totalMinted = stateBlock.GetPostMinted(epochNumIter).Big()
|
||||||
|
totalBurned = stateBlock.GetPostBurned(epochNumIter).Big()
|
||||||
|
if totalMinted.Sign() != 0 || totalBurned.Sign() != 0 {
|
||||||
|
// if previous epoch has non-zero total minted or non-zero total burned, break the loop
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
totalMinted.Add(totalMinted, rewardSum)
|
totalMinted.Add(totalMinted, rewardSum)
|
||||||
bigPower256 := new(big.Int).Lsh(big.NewInt(1), 256)
|
|
||||||
bigMaxU256 := new(big.Int).Sub(bigPower256, big.NewInt(1))
|
|
||||||
// if overflow, set to maxU256 and log a warning
|
// if overflow, set to maxU256 and log a warning
|
||||||
if totalMinted.Cmp(bigMaxU256) >= 0 {
|
if totalMinted.Cmp(math.MaxBig256) > 0 {
|
||||||
totalMinted.Set(bigMaxU256)
|
totalMinted.Set(math.MaxBig256)
|
||||||
log.Warn("[HookReward] total minted overflow max u256")
|
log.Warn("[HookReward] total minted overflow max u256")
|
||||||
}
|
}
|
||||||
log.Debug("[HookReward] total minted in hook", "value", totalMinted)
|
log.Debug("[HookReward] total minted in hook", "value", totalMinted)
|
||||||
stateBlock.PutTotalMinted(common.BigToHash(totalMinted))
|
stateBlock.PutPostMinted(epochNum, common.BigToHash(totalMinted))
|
||||||
stateBlock.PutLastEpochNum(common.Uint64ToHash(epochNum))
|
stateBlock.PutPostRewardBlock(epochNum, common.Uint64ToHash(number))
|
||||||
|
// Record total burned into statedb
|
||||||
|
totalBurned.Add(totalBurned, burnedInOneEpoch)
|
||||||
|
// if overflow, set to maxU256 and log a warning
|
||||||
|
if totalBurned.Cmp(math.MaxBig256) > 0 {
|
||||||
|
totalBurned.Set(math.MaxBig256)
|
||||||
|
log.Warn("[HookReward] total burned overflow max u256")
|
||||||
|
}
|
||||||
|
stateBlock.PutPostBurned(epochNum, common.BigToHash(totalBurned))
|
||||||
// Increment nonce so that statedb does not treat it as empty account
|
// Increment nonce so that statedb does not treat it as empty account
|
||||||
stateBlock.IncrementMintedRecordNonce()
|
stateBlock.IncrementMintedRecordNonce()
|
||||||
}
|
}
|
||||||
|
|
@ -388,7 +408,7 @@ func AttachConsensusV2Hooks(adaptor *XDPoS.XDPoS, bc *core.BlockChain, chainConf
|
||||||
}
|
}
|
||||||
|
|
||||||
// get signing transaction sender count
|
// get signing transaction sender count
|
||||||
func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, parentState *state.StateDB, currentConfig *params.V2Config) (map[Beneficiary]map[common.Address]*RewardLog, error) {
|
func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *types.Header, parentState *state.StateDB, currentConfig *params.V2Config) (map[Beneficiary]map[common.Address]*RewardLog, *big.Int, error) {
|
||||||
// header should be a new epoch switch block
|
// header should be a new epoch switch block
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
rewardEpochCount := 2
|
rewardEpochCount := 2
|
||||||
|
|
@ -400,9 +420,11 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
||||||
|
|
||||||
mapBlkHash := map[uint64]common.Hash{}
|
mapBlkHash := map[uint64]common.Hash{}
|
||||||
|
|
||||||
|
burnedInOneEpoch := new(big.Int)
|
||||||
|
|
||||||
// prevent overflow
|
// prevent overflow
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
return signers, nil
|
return signers, burnedInOneEpoch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
data := make(map[common.Hash][]common.Address)
|
data := make(map[common.Hash][]common.Address)
|
||||||
|
|
@ -417,11 +439,15 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
||||||
h = chain.GetHeader(parentHash, i)
|
h = chain.GetHeader(parentHash, i)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
log.Error("[GetSigningTxCount] fail to get header", "number", i, "hash", parentHash)
|
log.Error("[GetSigningTxCount] fail to get header", "number", i, "hash", parentHash)
|
||||||
return nil, fmt.Errorf("fail to get header in GetSigningTxCount at number: %v, hash: %v", i, parentHash)
|
return nil, burnedInOneEpoch, fmt.Errorf("fail to get header in GetSigningTxCount at number: %v, hash: %v", i, parentHash)
|
||||||
|
}
|
||||||
|
if epochCount == 0 && h.BaseFee != nil {
|
||||||
|
// add burned for the first epoch during loop
|
||||||
|
burnedInOneEpoch.Add(burnedInOneEpoch, new(big.Int).Mul(h.BaseFee, new(big.Int).SetUint64(h.GasUsed)))
|
||||||
}
|
}
|
||||||
isEpochSwitch, _, err := c.IsEpochSwitch(h)
|
isEpochSwitch, _, err := c.IsEpochSwitch(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, burnedInOneEpoch, err
|
||||||
}
|
}
|
||||||
if isEpochSwitch && i != chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
if isEpochSwitch && i != chain.Config().XDPoS.V2.SwitchBlock.Uint64()+1 {
|
||||||
epochCount += 1
|
epochCount += 1
|
||||||
|
|
@ -490,7 +516,7 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
||||||
}
|
}
|
||||||
// prevent overflow
|
// prevent overflow
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return signers, nil
|
return signers, burnedInOneEpoch, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,7 +561,7 @@ func GetSigningTxCount(c *XDPoS.XDPoS, chain consensus.ChainReader, header *type
|
||||||
|
|
||||||
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
|
log.Info("Calculate reward at checkpoint", "startBlock", startBlockNumber, "endBlock", endBlockNumber)
|
||||||
|
|
||||||
return signers, nil
|
return signers, burnedInOneEpoch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate reward for signers.
|
// Calculate reward for signers.
|
||||||
|
|
|
||||||
|
|
@ -2617,25 +2617,85 @@ func (api *BlockChainAPI) GetStakerROIMasternode(masternode common.Address) floa
|
||||||
return 100.0 / float64(totalCap.Div(totalCap, voterRewardAYear).Uint64())
|
return 100.0 / float64(totalCap.Div(totalCap, voterRewardAYear).Uint64())
|
||||||
}
|
}
|
||||||
|
|
||||||
type currentTotalMinted struct {
|
type supplyV1 struct {
|
||||||
TotalMinted *hexutil.Big `json:"totalMinted"`
|
Minted *hexutil.Big `json:"minted"`
|
||||||
LastEpochNum *hexutil.Big `json:"lastEpochNum"`
|
}
|
||||||
|
|
||||||
|
type supplyV2 struct {
|
||||||
|
Minted *hexutil.Big `json:"minted"`
|
||||||
|
Burned *hexutil.Big `json:"burned"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type tokenSupply struct {
|
||||||
|
V1 *supplyV1 `json:"v1"`
|
||||||
|
V2 *supplyV2 `json:"v2"`
|
||||||
|
Minted *hexutil.Big `json:"minted"`
|
||||||
|
UpgradeEpochNum *hexutil.Big `json:"upgradeEpochNum"`
|
||||||
|
EpochNum *hexutil.Big `json:"epochNum"`
|
||||||
BlockHash common.Hash `json:"blockHash"`
|
BlockHash common.Hash `json:"blockHash"`
|
||||||
BlockNumber *hexutil.Big `json:"blockNumber"`
|
BlockNumber *hexutil.Big `json:"blockNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *BlockChainAPI) GetCurrentTotalMinted(ctx context.Context) (*currentTotalMinted, error) {
|
func (s *BlockChainAPI) GetTokenStats(ctx context.Context, epochNr rpc.EpochNumber) (*tokenSupply, error) {
|
||||||
statedb, header, err := api.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
|
engine, ok := s.b.Engine().(*XDPoS.XDPoS)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("undefined XDPoS consensus engine")
|
||||||
|
}
|
||||||
|
statedb, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber)
|
||||||
|
nonce := statedb.GetNonce(common.MintedRecordAddressBinary)
|
||||||
|
if nonce == 0 {
|
||||||
|
return nil, errors.New("mintedRecordAddress is not initialized due to Reward Upgrade is not applied")
|
||||||
|
}
|
||||||
|
currentRound, err := engine.EngineV2.GetRoundNumber(header)
|
||||||
|
currentEpoch := s.b.ChainConfig().XDPoS.V2.SwitchEpoch + uint64(currentRound)/s.b.ChainConfig().XDPoS.Epoch
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
totalMinted := statedb.GetTotalMinted().Big()
|
onsetEpoch := statedb.GetMintedRecordOnsetEpoch().Big().Uint64()
|
||||||
lastEpochNum := statedb.GetLastEpochNum().Big()
|
if epochNr >= 0 {
|
||||||
result := ¤tTotalMinted{
|
if uint64(epochNr) < onsetEpoch {
|
||||||
TotalMinted: (*hexutil.Big)(totalMinted),
|
return nil, errors.New("epoch number is before reward upgrade")
|
||||||
LastEpochNum: (*hexutil.Big)(lastEpochNum),
|
}
|
||||||
BlockHash: header.Hash(),
|
if uint64(epochNr) > currentEpoch {
|
||||||
BlockNumber: (*hexutil.Big)(header.Number),
|
return nil, errors.New("epoch number is after current epoch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
epochNum := uint64(epochNr)
|
||||||
|
if epochNr == rpc.LatestEpochNumber {
|
||||||
|
epochNum = currentEpoch
|
||||||
|
}
|
||||||
|
postMinted := statedb.GetPostMinted(epochNum).Big()
|
||||||
|
number := statedb.GetPostRewardBlock(epochNum).Big()
|
||||||
|
targetHeader, err := s.b.HeaderByNumber(ctx, rpc.BlockNumber(number.Int64()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
config := s.b.ChainConfig().XDPoS
|
||||||
|
if config == nil {
|
||||||
|
return nil, errors.New("xdpos config is nil")
|
||||||
|
}
|
||||||
|
preEpochMinted := new(big.Int).Mul(new(big.Int).SetUint64(config.Reward), new(big.Int).SetUint64(params.Ether))
|
||||||
|
onsetEpochMinus := onsetEpoch
|
||||||
|
if onsetEpochMinus > 0 {
|
||||||
|
onsetEpochMinus--
|
||||||
|
} else {
|
||||||
|
log.Warn("OnsetEpoch is 0 which could not happen", epochNum)
|
||||||
|
}
|
||||||
|
preMinted := new(big.Int).Mul(preEpochMinted, new(big.Int).SetUint64(onsetEpochMinus))
|
||||||
|
postBurned := statedb.GetPostBurned(epochNum).Big()
|
||||||
|
result := &tokenSupply{
|
||||||
|
V1: &supplyV1{
|
||||||
|
Minted: (*hexutil.Big)(preMinted),
|
||||||
|
},
|
||||||
|
V2: &supplyV2{
|
||||||
|
Minted: (*hexutil.Big)(postMinted),
|
||||||
|
Burned: (*hexutil.Big)(postBurned),
|
||||||
|
},
|
||||||
|
Minted: (*hexutil.Big)(new(big.Int).Add(postMinted, preMinted)),
|
||||||
|
UpgradeEpochNum: (*hexutil.Big)(new(big.Int).SetUint64(onsetEpoch)),
|
||||||
|
EpochNum: (*hexutil.Big)(new(big.Int).SetUint64(epochNum)),
|
||||||
|
BlockHash: targetHeader.Hash(),
|
||||||
|
BlockNumber: (*hexutil.Big)(number),
|
||||||
}
|
}
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -578,9 +578,9 @@ web3._extend({
|
||||||
params: 1,
|
params: 1,
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'getCurrentTotalMinted',
|
name: 'getTokenStats',
|
||||||
call: 'eth_getCurrentTotalMinted',
|
call: 'eth_getTokenStats',
|
||||||
params: 0,
|
params: 1,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
properties: [
|
properties: [
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue