github.com/klaytn/klaytn@v1.10.2/governance/api.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package governance
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"strings"
    24  
    25  	"github.com/klaytn/klaytn/common/hexutil"
    26  
    27  	"github.com/klaytn/klaytn/common"
    28  	"github.com/klaytn/klaytn/networks/rpc"
    29  	"github.com/klaytn/klaytn/params"
    30  	"github.com/klaytn/klaytn/reward"
    31  )
    32  
    33  type PublicGovernanceAPI struct {
    34  	governance Engine // Node interfaced by this API
    35  }
    36  
    37  type returnTally struct {
    38  	Key                string
    39  	Value              interface{}
    40  	ApprovalPercentage float64
    41  }
    42  
    43  func NewGovernanceAPI(gov Engine) *PublicGovernanceAPI {
    44  	return &PublicGovernanceAPI{governance: gov}
    45  }
    46  
    47  type GovernanceKlayAPI struct {
    48  	governance Engine
    49  	chain      blockChain
    50  }
    51  
    52  func NewGovernanceKlayAPI(gov Engine, chain blockChain) *GovernanceKlayAPI {
    53  	return &GovernanceKlayAPI{governance: gov, chain: chain}
    54  }
    55  
    56  var (
    57  	errUnknownBlock           = errors.New("Unknown block")
    58  	errNotAvailableInThisMode = errors.New("In current governance mode, voting power is not available")
    59  	errSetDefaultFailure      = errors.New("Failed to set a default value")
    60  	errPermissionDenied       = errors.New("You don't have the right to vote")
    61  	errRemoveSelf             = errors.New("You can't vote on removing yourself")
    62  	errInvalidKeyValue        = errors.New("Your vote couldn't be placed. Please check your vote's key and value")
    63  	errInvalidLowerBound      = errors.New("lowerboundbasefee cannot be set exceeding upperboundbasefee")
    64  	errInvalidUpperBound      = errors.New("upperboundbasefee cannot be set lower than lowerboundbasefee")
    65  )
    66  
    67  func (api *GovernanceKlayAPI) GetStakingInfo(num *rpc.BlockNumber) (*reward.StakingInfo, error) {
    68  	return getStakingInfo(api.governance, num)
    69  }
    70  
    71  // TODO-Klaytn-Mantle: deprecate this
    72  func (api *GovernanceKlayAPI) GovParamsAt(num *rpc.BlockNumber) (map[string]interface{}, error) {
    73  	return getParams(api.governance, num)
    74  }
    75  
    76  func (api *GovernanceKlayAPI) GetParams(num *rpc.BlockNumber) (map[string]interface{}, error) {
    77  	return getParams(api.governance, num)
    78  }
    79  
    80  func (api *GovernanceKlayAPI) NodeAddress() common.Address {
    81  	return api.governance.NodeAddress()
    82  }
    83  
    84  // GasPriceAt returns the base fee of the given block in peb,
    85  // or returns unit price by using governance if there is no base fee set in header,
    86  // or returns gas price of txpool if the block is pending block.
    87  func (api *GovernanceKlayAPI) GasPriceAt(num *rpc.BlockNumber) (*hexutil.Big, error) {
    88  	if num == nil || *num == rpc.LatestBlockNumber {
    89  		header := api.chain.CurrentBlock().Header()
    90  		if header.BaseFee == nil {
    91  			pset, err := api.governance.EffectiveParams(header.Number.Uint64() + 1)
    92  			if err != nil {
    93  				return nil, err
    94  			}
    95  			return (*hexutil.Big)(new(big.Int).SetUint64(pset.UnitPrice())), nil
    96  		}
    97  		return (*hexutil.Big)(header.BaseFee), nil
    98  	} else if *num == rpc.PendingBlockNumber {
    99  		txpool := api.governance.GetTxPool()
   100  		return (*hexutil.Big)(txpool.GasPrice()), nil
   101  	} else {
   102  		blockNum := num.Uint64()
   103  
   104  		// Return the BaseFee in header at the block number
   105  		header := api.chain.GetHeaderByNumber(blockNum)
   106  		if blockNum > api.chain.CurrentBlock().NumberU64() || header == nil {
   107  			return nil, errUnknownBlock
   108  		} else if header.BaseFee != nil {
   109  			return (*hexutil.Big)(header.BaseFee), nil
   110  		}
   111  
   112  		// Return the UnitPrice in governance data at the block number
   113  		if ret, err := api.GasPriceAtNumber(blockNum); err != nil {
   114  			return nil, err
   115  		} else {
   116  			return (*hexutil.Big)(new(big.Int).SetUint64(ret)), nil
   117  		}
   118  	}
   119  }
   120  
   121  // GetRewards returns detailed information of the block reward at a given block number.
   122  func (api *GovernanceKlayAPI) GetRewards(num *rpc.BlockNumber) (*reward.RewardSpec, error) {
   123  	blockNumber := uint64(0)
   124  	if num == nil || *num == rpc.LatestBlockNumber {
   125  		blockNumber = api.chain.CurrentBlock().NumberU64()
   126  	} else {
   127  		blockNumber = uint64(num.Int64())
   128  	}
   129  
   130  	header := api.chain.GetHeaderByNumber(blockNumber)
   131  	if header == nil {
   132  		return nil, fmt.Errorf("the block does not exist (block number: %d)", blockNumber)
   133  	}
   134  
   135  	rules := api.chain.Config().Rules(new(big.Int).SetUint64(blockNumber))
   136  	pset, err := api.governance.EffectiveParams(blockNumber)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	rewardParamNum := reward.CalcRewardParamBlock(header.Number.Uint64(), pset.Epoch(), rules)
   141  	rewardParamSet, err := api.governance.EffectiveParams(rewardParamNum)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	return reward.GetBlockReward(header, rules, rewardParamSet)
   147  }
   148  
   149  func (api *GovernanceKlayAPI) ChainConfig() *params.ChainConfig {
   150  	num := rpc.LatestBlockNumber
   151  	return getChainConfig(api.governance, &num)
   152  }
   153  
   154  // TODO-Klaytn-Mantle: deprecate this
   155  func (api *GovernanceKlayAPI) ChainConfigAt(num *rpc.BlockNumber) *params.ChainConfig {
   156  	return getChainConfig(api.governance, num)
   157  }
   158  
   159  func (api *GovernanceKlayAPI) GetChainConfig(num *rpc.BlockNumber) *params.ChainConfig {
   160  	return getChainConfig(api.governance, num)
   161  }
   162  
   163  // Vote injects a new vote for governance targets such as unitprice and governingnode.
   164  func (api *PublicGovernanceAPI) Vote(key string, val interface{}) (string, error) {
   165  	blockNumber := api.governance.BlockChain().CurrentBlock().NumberU64()
   166  	pset, err := api.governance.EffectiveParams(blockNumber + 1)
   167  	if err != nil {
   168  		return "", err
   169  	}
   170  	gMode := pset.GovernanceModeInt()
   171  	gNode := pset.GoverningNode()
   172  
   173  	if gMode == params.GovernanceMode_Single && gNode != api.governance.NodeAddress() {
   174  		return "", errPermissionDenied
   175  	}
   176  	vote, ok := api.governance.ValidateVote(&GovernanceVote{Key: strings.ToLower(key), Value: val})
   177  	if !ok {
   178  		return "", errInvalidKeyValue
   179  	}
   180  	if vote.Key == "governance.removevalidator" {
   181  		if api.isRemovingSelf(val.(string)) {
   182  			return "", errRemoveSelf
   183  		}
   184  	}
   185  	if vote.Key == "kip71.lowerboundbasefee" {
   186  		if vote.Value.(uint64) > pset.UpperBoundBaseFee() {
   187  			return "", errInvalidLowerBound
   188  		}
   189  	}
   190  	if vote.Key == "kip71.upperboundbasefee" {
   191  		if vote.Value.(uint64) < pset.LowerBoundBaseFee() {
   192  			return "", errInvalidUpperBound
   193  		}
   194  	}
   195  	if api.governance.AddVote(key, val) {
   196  		return "Your vote is prepared. It will be put into the block header or applied when your node generates a block as a proposer. Note that your vote may be duplicate.", nil
   197  	}
   198  	return "", errInvalidKeyValue
   199  }
   200  
   201  func (api *PublicGovernanceAPI) isRemovingSelf(val string) bool {
   202  	for _, str := range strings.Split(val, ",") {
   203  		str = strings.Trim(str, " ")
   204  		if common.HexToAddress(str) == api.governance.NodeAddress() {
   205  			return true
   206  		}
   207  	}
   208  	return false
   209  }
   210  
   211  func (api *PublicGovernanceAPI) ShowTally() []*returnTally {
   212  	ret := []*returnTally{}
   213  
   214  	for _, val := range api.governance.GetGovernanceTalliesCopy() {
   215  		item := &returnTally{
   216  			Key:                val.Key,
   217  			Value:              val.Value,
   218  			ApprovalPercentage: float64(val.Votes) / float64(api.governance.TotalVotingPower()) * 100,
   219  		}
   220  		ret = append(ret, item)
   221  	}
   222  
   223  	return ret
   224  }
   225  
   226  func (api *PublicGovernanceAPI) TotalVotingPower() (float64, error) {
   227  	if !api.isGovernanceModeBallot() {
   228  		return 0, errNotAvailableInThisMode
   229  	}
   230  	return float64(api.governance.TotalVotingPower()) / 1000.0, nil
   231  }
   232  
   233  // TODO-Klaytn-Mantle: deprecate this
   234  func (api *PublicGovernanceAPI) ItemsAt(num *rpc.BlockNumber) (map[string]interface{}, error) {
   235  	return getParams(api.governance, num)
   236  }
   237  
   238  func (api *PublicGovernanceAPI) GetParams(num *rpc.BlockNumber) (map[string]interface{}, error) {
   239  	return getParams(api.governance, num)
   240  }
   241  
   242  func getParams(governance Engine, num *rpc.BlockNumber) (map[string]interface{}, error) {
   243  	blockNumber := uint64(0)
   244  	if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
   245  		blockNumber = governance.BlockChain().CurrentBlock().NumberU64()
   246  	} else {
   247  		blockNumber = uint64(num.Int64())
   248  	}
   249  
   250  	pset, err := governance.EffectiveParams(blockNumber)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	return pset.StrMap(), nil
   255  }
   256  
   257  func (api *PublicGovernanceAPI) GetStakingInfo(num *rpc.BlockNumber) (*reward.StakingInfo, error) {
   258  	return getStakingInfo(api.governance, num)
   259  }
   260  
   261  func getStakingInfo(governance Engine, num *rpc.BlockNumber) (*reward.StakingInfo, error) {
   262  	blockNumber := uint64(0)
   263  	if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
   264  		blockNumber = governance.BlockChain().CurrentBlock().NumberU64()
   265  	} else {
   266  		blockNumber = uint64(num.Int64())
   267  	}
   268  	return reward.GetStakingInfo(blockNumber), nil
   269  }
   270  
   271  func (api *PublicGovernanceAPI) PendingChanges() map[string]interface{} {
   272  	return api.governance.PendingChanges()
   273  }
   274  
   275  func (api *PublicGovernanceAPI) Votes() []GovernanceVote {
   276  	return api.governance.Votes()
   277  }
   278  
   279  func (api *PublicGovernanceAPI) IdxCache() []uint64 {
   280  	return api.governance.IdxCache()
   281  }
   282  
   283  func (api *PublicGovernanceAPI) IdxCacheFromDb() []uint64 {
   284  	return api.governance.IdxCacheFromDb()
   285  }
   286  
   287  // TODO-Klaytn: Return error if invalid input is given such as pending or a too big number
   288  func (api *PublicGovernanceAPI) ItemCacheFromDb(num *rpc.BlockNumber) map[string]interface{} {
   289  	blockNumber := uint64(0)
   290  	if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
   291  		blockNumber = api.governance.BlockChain().CurrentBlock().NumberU64()
   292  	} else {
   293  		blockNumber = uint64(num.Int64())
   294  	}
   295  	ret, _ := api.governance.DB().ReadGovernance(blockNumber)
   296  	return ret
   297  }
   298  
   299  type VoteList struct {
   300  	Key      string
   301  	Value    interface{}
   302  	Casted   bool
   303  	BlockNum uint64
   304  }
   305  
   306  func (api *PublicGovernanceAPI) MyVotes() []*VoteList {
   307  	ret := []*VoteList{}
   308  
   309  	for k, v := range api.governance.GetVoteMapCopy() {
   310  		item := &VoteList{
   311  			Key:      k,
   312  			Value:    v.Value,
   313  			Casted:   v.Casted,
   314  			BlockNum: v.Num,
   315  		}
   316  		ret = append(ret, item)
   317  	}
   318  
   319  	return ret
   320  }
   321  
   322  func (api *PublicGovernanceAPI) MyVotingPower() (float64, error) {
   323  	if !api.isGovernanceModeBallot() {
   324  		return 0, errNotAvailableInThisMode
   325  	}
   326  	return float64(api.governance.MyVotingPower()) / 1000.0, nil
   327  }
   328  
   329  func (api *PublicGovernanceAPI) ChainConfig() *params.ChainConfig {
   330  	num := rpc.LatestBlockNumber
   331  	return getChainConfig(api.governance, &num)
   332  }
   333  
   334  // TODO-Klaytn-Mantle: deprecate this
   335  func (api *PublicGovernanceAPI) ChainConfigAt(num *rpc.BlockNumber) *params.ChainConfig {
   336  	return getChainConfig(api.governance, num)
   337  }
   338  
   339  func (api *PublicGovernanceAPI) GetChainConfig(num *rpc.BlockNumber) *params.ChainConfig {
   340  	return getChainConfig(api.governance, num)
   341  }
   342  
   343  func getChainConfig(governance Engine, num *rpc.BlockNumber) *params.ChainConfig {
   344  	var blocknum uint64
   345  	if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
   346  		blocknum = governance.BlockChain().CurrentBlock().NumberU64()
   347  	} else {
   348  		blocknum = num.Uint64()
   349  	}
   350  
   351  	pset, err := governance.EffectiveParams(blocknum)
   352  	if err != nil {
   353  		return nil
   354  	}
   355  
   356  	latestConfig := governance.BlockChain().Config()
   357  	config := pset.ToChainConfig()
   358  	config.ChainID = latestConfig.ChainID
   359  	config.IstanbulCompatibleBlock = latestConfig.IstanbulCompatibleBlock
   360  	config.LondonCompatibleBlock = latestConfig.LondonCompatibleBlock
   361  	config.EthTxTypeCompatibleBlock = latestConfig.EthTxTypeCompatibleBlock
   362  	config.MagmaCompatibleBlock = latestConfig.MagmaCompatibleBlock
   363  	config.KoreCompatibleBlock = latestConfig.KoreCompatibleBlock
   364  	config.Kip103CompatibleBlock = latestConfig.Kip103CompatibleBlock
   365  	config.Kip103ContractAddress = latestConfig.Kip103ContractAddress
   366  
   367  	return config
   368  }
   369  
   370  func (api *PublicGovernanceAPI) NodeAddress() common.Address {
   371  	return api.governance.NodeAddress()
   372  }
   373  
   374  func (api *PublicGovernanceAPI) isGovernanceModeBallot() bool {
   375  	blockNumber := api.governance.BlockChain().CurrentBlock().NumberU64()
   376  	pset, err := api.governance.EffectiveParams(blockNumber + 1)
   377  	if err != nil {
   378  		return false
   379  	}
   380  	gMode := pset.GovernanceModeInt()
   381  	return gMode == params.GovernanceMode_Ballot
   382  }
   383  
   384  func (api *GovernanceKlayAPI) GasPriceAtNumber(num uint64) (uint64, error) {
   385  	pset, err := api.governance.EffectiveParams(num)
   386  	if err != nil {
   387  		logger.Error("Failed to retrieve unit price", "err", err)
   388  		return 0, err
   389  	}
   390  	return pset.UnitPrice(), nil
   391  }
   392  
   393  // Disabled APIs
   394  // func (api *GovernanceKlayAPI) GetTxGasHumanReadable(num *rpc.BlockNumber) (uint64, error) {
   395  // 	if num == nil || *num == rpc.LatestBlockNumber || *num == rpc.PendingBlockNumber {
   396  // 		// If the value hasn't been set in governance, set it with default value
   397  // 		if ret := api.governance.GetGovernanceValue(params.ConstTxGasHumanReadable); ret == nil {
   398  // 			return api.setDefaultTxGasHumanReadable()
   399  // 		} else {
   400  // 			return ret.(uint64), nil
   401  // 		}
   402  // 	} else {
   403  // 		blockNum := num.Int64()
   404  //
   405  // 		if blockNum > api.chain.CurrentBlock().NumberU64() {
   406  // 			return 0, errUnknownBlock
   407  // 		}
   408  //
   409  // 		if ret, err := api.governance.GetGovernanceItemAtNumber(uint64(blockNum), GovernanceKeyMapReverse[params.ConstTxGasHumanReadable]); err == nil && ret != nil {
   410  // 			return ret.(uint64), nil
   411  // 		} else {
   412  // 			logger.Error("Failed to retrieve TxGasHumanReadable, sending default value", "err", err)
   413  // 			return api.setDefaultTxGasHumanReadable()
   414  // 		}
   415  // 	}
   416  // }
   417  //
   418  // func (api *GovernanceKlayAPI) setDefaultTxGasHumanReadable() (uint64, error) {
   419  // 	err := api.governance.currentSet.SetValue(params.ConstTxGasHumanReadable, params.TxGasHumanReadable)
   420  // 	if err != nil {
   421  // 		return 0, errSetDefaultFailure
   422  // 	} else {
   423  // 		return params.TxGasHumanReadable, nil
   424  // 	}
   425  // }