diff --git a/api/service/explorer/service.go b/api/service/explorer/service.go index d681d2a2f..cc4e1eed0 100644 --- a/api/service/explorer/service.go +++ b/api/service/explorer/service.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "fmt" - "math/big" "net" "net/http" "path" @@ -22,7 +21,6 @@ import ( "github.com/harmony-one/harmony/hmy" "github.com/harmony-one/harmony/hmy/tracers" "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" @@ -212,14 +210,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"` @@ -228,48 +218,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) @@ -280,17 +245,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) } @@ -305,7 +265,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) diff --git a/cmd/harmony/flags.go b/cmd/harmony/flags.go index 3dbd28f1c..282746ebe 100644 --- a/cmd/harmony/flags.go +++ b/cmd/harmony/flags.go @@ -320,10 +320,6 @@ func applyGeneralFlags(cmd *cobra.Command, config *harmonyconfig.HarmonyConfig) config.General.NodeType = cli.GetStringFlagValue(cmd, legacyNodeTypeFlag) } - if config.General.NodeType == nodeTypeExplorer { - config.General.IsArchival = true - } - if cli.IsFlagChanged(cmd, shardIDFlag) { config.General.ShardID = cli.GetIntFlagValue(cmd, shardIDFlag) } else if cli.IsFlagChanged(cmd, legacyShardIDFlag) { diff --git a/cmd/harmony/flags_test.go b/cmd/harmony/flags_test.go index b0e4200d3..bd72fc709 100644 --- a/cmd/harmony/flags_test.go +++ b/cmd/harmony/flags_test.go @@ -198,7 +198,7 @@ func TestGeneralFlags(t *testing.T) { NodeType: "explorer", NoStaking: false, ShardID: 0, - IsArchival: true, + IsArchival: false, DataDir: "./", }, }, diff --git a/internal/chain/supply.go b/internal/chain/supply.go index 6e956e541..2890d88a3 100644 --- a/internal/chain/supply.go +++ b/internal/chain/supply.go @@ -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 +} diff --git a/rpc/blockchain.go b/rpc/blockchain.go index 52ed9d6e5..599bf6cc1 100644 --- a/rpc/blockchain.go +++ b/rpc/blockchain.go @@ -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 ..