Fix circulating supply (#3802)

* [rpc] updated rpc to GetCirculationSupply to sub token burnt

* [explorer] add a small fix

* [rpc] fix at getInaccessible tokens

* [rpc] added fix at header.Root
pull/3820/head
Jacky Wang 3 years ago committed by GitHub
parent da21bd11ec
commit 768a570363
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 68
      api/service/explorer/service.go
  2. 93
      internal/chain/supply.go
  3. 5
      rpc/blockchain.go

@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
"math/big"
"net"
"net/http"
"path"
@ -21,7 +20,6 @@ import (
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/internal/chain"
"github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/numeric"
@ -202,14 +200,6 @@ func (s *Service) IsAvailable() bool {
return s.storage.available.IsSet()
}
var (
// InaccessibleAddresses are a list of known eth addresses that cannot spend ONE tokens.
InaccessibleAddresses = []ethCommon.Address{
// one10000000000000000000000000000dead5shlag
ethCommon.HexToAddress("0x7bDeF7Bdef7BDeF7BDEf7bDef7bdef7bdeF6E7AD"),
}
)
// InaccessibleAddressInfo ..
type InaccessibleAddressInfo struct {
EthAddress ethCommon.Address `json:"eth-address"`
@ -218,48 +208,23 @@ type InaccessibleAddressInfo struct {
Nonce uint64 `json:"nonce"`
}
// getAllInaccessibleAddresses information according to InaccessibleAddresses
func (s *Service) getAllInaccessibleAddresses() ([]*InaccessibleAddressInfo, error) {
state, err := s.blockchain.StateAt(s.blockchain.CurrentHeader().Root())
if err != nil {
return nil, err
}
accs := []*InaccessibleAddressInfo{}
for _, addr := range InaccessibleAddresses {
accs = append(accs, &InaccessibleAddressInfo{
EthAddress: addr,
Address: common.MustAddressToBech32(addr),
Balance: numeric.NewDecFromBigIntWithPrec(state.GetBalance(addr), 18),
Nonce: state.GetNonce(addr),
})
}
return accs, nil
}
// getTotalInaccessibleTokens in ONE at the latest header.
func (s *Service) getTotalInaccessibleTokens() (numeric.Dec, error) {
addrInfos, err := s.getAllInaccessibleAddresses()
if err != nil {
return numeric.Dec{}, err
}
total := numeric.NewDecFromBigIntWithPrec(big.NewInt(0), 18)
for _, addr := range addrInfos {
total = total.Add(addr.Balance)
}
return total, nil
}
// GetInaccessibleAddressInfo serves /burn-addresses end-point.
func (s *Service) GetInaccessibleAddressInfo(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
accInfos, err := s.getAllInaccessibleAddresses()
accInfos, err := chain.GetInaccessibleAddressInfo(s.blockchain)
if err != nil {
utils.Logger().Warn().Err(err).Msg("unable to fetch inaccessible addresses")
w.WriteHeader(http.StatusInternalServerError)
}
display := make([]*InaccessibleAddressInfo, 0, len(accInfos))
for _, acc := range accInfos {
display = append(display, &InaccessibleAddressInfo{
EthAddress: acc.EthAddress,
Address: acc.Address,
Balance: acc.Balance,
Nonce: acc.Nonce,
})
}
if err := json.NewEncoder(w).Encode(accInfos); err != nil {
utils.Logger().Warn().Msg("cannot JSON-encode inaccessible account info")
w.WriteHeader(http.StatusInternalServerError)
@ -270,17 +235,12 @@ func (s *Service) GetInaccessibleAddressInfo(w http.ResponseWriter, r *http.Requ
// Note that known InaccessibleAddresses have their funds removed from the supply for this endpoint.
func (s *Service) GetCirculatingSupply(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
circulatingSupply, err := chain.GetCirculatingSupply(context.Background(), s.blockchain)
cs, err := chain.GetCirculatingSupply(s.blockchain)
if err != nil {
utils.Logger().Warn().Err(err).Msg("unable to fetch circulating supply")
w.WriteHeader(http.StatusInternalServerError)
}
totalInaccessible, err := s.getTotalInaccessibleTokens()
if err != nil {
utils.Logger().Warn().Err(err).Msg("unable to fetch inaccessible tokens")
utils.Logger().Warn().Msg("Failed to get circulating supply")
w.WriteHeader(http.StatusInternalServerError)
}
if err := json.NewEncoder(w).Encode(circulatingSupply.Sub(totalInaccessible)); err != nil {
if err := json.NewEncoder(w).Encode(cs); err != nil {
utils.Logger().Warn().Msg("cannot JSON-encode circulating supply")
w.WriteHeader(http.StatusInternalServerError)
}
@ -295,7 +255,7 @@ func (s *Service) GetTotalSupply(w http.ResponseWriter, r *http.Request) {
utils.Logger().Warn().Err(err).Msg("unable to fetch total supply")
w.WriteHeader(http.StatusInternalServerError)
}
totalInaccessible, err := s.getTotalInaccessibleTokens()
totalInaccessible, err := chain.GetInaccessibleTokens(s.blockchain)
if err != nil {
utils.Logger().Warn().Err(err).Msg("unable to fetch inaccessible tokens")
w.WriteHeader(http.StatusInternalServerError)

@ -1,29 +1,75 @@
package chain
import (
"context"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/shard"
stakingReward "github.com/harmony-one/harmony/staking/reward"
"github.com/pkg/errors"
)
// GetCirculatingSupply using the following formula:
// Circulating supply calculation
var (
// InaccessibleAddresses are a list of known eth addresses that cannot spend ONE tokens.
InaccessibleAddresses = []common.Address{
// one10000000000000000000000000000dead5shlag
common.HexToAddress("0x7bDeF7Bdef7BDeF7BDEf7bDef7bdef7bdeF6E7AD"),
}
)
// InaccessibleAddressInfo is the structure for inaccessible addresses
type InaccessibleAddressInfo struct {
EthAddress common.Address
Address string // One address
Balance numeric.Dec
Nonce uint64
}
// GetCirculatingSupply get the circulating supply.
// The value is the total circulating supply sub the tokens burnt at
// inaccessible addresses.
// WARNING: only works on beacon chain if in staking era.
func GetCirculatingSupply(chain engine.ChainReader) (numeric.Dec, error) {
total, err := getTotalCirculatingSupply(chain)
if err != nil {
return numeric.Dec{}, err
}
invalid, err := getAllInaccessibleTokens(chain)
if err != nil {
return numeric.Dec{}, err
}
if total.LT(invalid) {
return numeric.Dec{}, errors.New("FATAL: negative circulating supply")
}
return total.Sub(invalid), nil
}
// GetInaccessibleAddressInfo return the information of all inaccessible
// addresses.
func GetInaccessibleAddressInfo(chain engine.ChainReader) ([]*InaccessibleAddressInfo, error) {
return getAllInaccessibleAddresses(chain)
}
// GetInaccessibleTokens get the total inaccessible tokens.
// The amount is the sum of balance at all inaccessible addresses.
func GetInaccessibleTokens(chain engine.ChainReader) (numeric.Dec, error) {
return getAllInaccessibleTokens(chain)
}
// getTotalCirculatingSupply using the following formula:
// (TotalInitialTokens * percentReleased) + PreStakingBlockRewards + StakingBlockRewards
//
// Note that PreStakingBlockRewards is set to the amount of rewards given out by the
// LAST BLOCK of the pre-staking era regardless of what the current block height is
// if network is in the pre-staking era. This is for implementation reasons, reference
// stakingReward.GetTotalPreStakingTokens for more details.
//
// WARNING: only works on beaconchain if in staking era.
func GetCirculatingSupply(
ctx context.Context, chain engine.ChainReader,
) (ret numeric.Dec, err error) {
func getTotalCirculatingSupply(chain engine.ChainReader) (ret numeric.Dec, err error) {
currHeader, timestamp := chain.CurrentHeader(), time.Now().Unix()
stakingBlockRewards := big.NewInt(0)
@ -44,3 +90,36 @@ func GetCirculatingSupply(
numeric.NewDecFromBigIntWithPrec(stakingBlockRewards, 18),
), nil
}
func getAllInaccessibleTokens(chain engine.ChainReader) (numeric.Dec, error) {
ais, err := getAllInaccessibleAddresses(chain)
if err != nil {
return numeric.Dec{}, err
}
total := numeric.NewDecFromBigIntWithPrec(big.NewInt(0), numeric.Precision)
for _, ai := range ais {
total = total.Add(ai.Balance)
}
return total, nil
}
func getAllInaccessibleAddresses(chain engine.ChainReader) ([]*InaccessibleAddressInfo, error) {
state, err := chain.StateAt(chain.CurrentHeader().Root())
if err != nil {
return nil, err
}
accs := make([]*InaccessibleAddressInfo, 0, len(InaccessibleAddresses))
for _, addr := range InaccessibleAddresses {
nonce := state.GetNonce(addr)
oneAddr, _ := common2.AddressToBech32(addr)
balance := state.GetBalance(addr)
accs = append(accs, &InaccessibleAddressInfo{
EthAddress: addr,
Address: oneAddr,
Balance: numeric.NewDecFromBigIntWithPrec(balance, numeric.Precision),
Nonce: nonce,
})
}
return accs, nil
}

@ -7,6 +7,8 @@ import (
"strconv"
"time"
"github.com/harmony-one/harmony/internal/chain"
"github.com/prometheus/client_golang/prometheus"
"github.com/ethereum/go-ethereum/common"
@ -15,7 +17,6 @@ import (
"golang.org/x/time/rate"
"github.com/harmony-one/harmony/hmy"
"github.com/harmony-one/harmony/internal/chain"
internal_common "github.com/harmony-one/harmony/internal/common"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
@ -767,7 +768,7 @@ func (s *PublicBlockchainService) GetTotalSupply(
func (s *PublicBlockchainService) GetCirculatingSupply(
ctx context.Context,
) (numeric.Dec, error) {
return chain.GetCirculatingSupply(ctx, s.hmy.BlockChain)
return chain.GetCirculatingSupply(s.hmy.BlockChain)
}
// GetStakingNetworkInfo ..

Loading…
Cancel
Save