github.com/klaytn/klaytn@v1.12.1/governance/mixed.go (about)

     1  // Copyright 2022 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  	"math/big"
    21  
    22  	"github.com/klaytn/klaytn/blockchain/types"
    23  	"github.com/klaytn/klaytn/common"
    24  	"github.com/klaytn/klaytn/consensus/istanbul"
    25  	"github.com/klaytn/klaytn/params"
    26  	"github.com/klaytn/klaytn/storage/database"
    27  )
    28  
    29  // MixedEngine consists of multiple governance engines
    30  //
    31  // Each parameter is added to a parameter set from one of the following sources:
    32  // The highest priority is 1, and falls back to lower ones if non-existent
    33  //  1. contractParams: ContractEngine items (when enabled)
    34  //  2. headerParams:   Header Governance items
    35  //  3. initialParams:  initial ChainConfig from genesis.json
    36  //  4. defaultParams:  Default params such as params.Default*
    37  //     Note that some items are not backed by defaultParams.
    38  type MixedEngine struct {
    39  	// The same ChainConfig instance as Blockchain.chainConfig, {cn, worker}.config
    40  	config *params.ChainConfig
    41  
    42  	initialParams *params.GovParamSet // initial ChainConfig
    43  	defaultParams *params.GovParamSet // default constants used as last fallback
    44  
    45  	currentParams *params.GovParamSet // latest params to be returned by CurrentParams()
    46  
    47  	db database.DBManager
    48  
    49  	// Subordinate engines
    50  	// contractGov is enabled when all the following conditions are met:
    51  	//   - Kore hardfork block has passed
    52  	//   - GovParamContract has been set
    53  	// contractGov can be ignored even if it is enabled for various reasons. To name a few:
    54  	//   - GovParam returns invalid parameters
    55  	//   - Calling GovParam reverted
    56  	// contractGov can throw critical error:
    57  	//   - headerGov.BlockChain() is nil -> Fix by calling gov.SetBlockChain(bc)
    58  	// headerGov cannot be disabled. However, its parameters can be ignored
    59  	// by the prior contract parameters
    60  	contractGov *ContractEngine
    61  	headerGov   *Governance
    62  
    63  	// for param update
    64  	txpool     txPool
    65  	blockchain blockChain
    66  }
    67  
    68  // newMixedEngine instantiate a new MixedEngine struct.
    69  // Only if doInit is true, subordinate engines will be initialized.
    70  func newMixedEngine(config *params.ChainConfig, db database.DBManager, doInit bool) *MixedEngine {
    71  	e := &MixedEngine{
    72  		config: config,
    73  		db:     db,
    74  	}
    75  
    76  	if p, err := params.NewGovParamSetChainConfig(config); err == nil {
    77  		e.initialParams = p
    78  		e.currentParams = p
    79  	} else {
    80  		logger.Crit("Error parsing initial ChainConfig", "err", err)
    81  	}
    82  
    83  	defaultMap := map[int]interface{}{
    84  		params.LowerBoundBaseFee:         params.DefaultLowerBoundBaseFee,
    85  		params.UpperBoundBaseFee:         params.DefaultUpperBoundBaseFee,
    86  		params.GasTarget:                 params.DefaultGasTarget,
    87  		params.MaxBlockGasUsedForBaseFee: params.DefaultMaxBlockGasUsedForBaseFee,
    88  		params.BaseFeeDenominator:        params.DefaultBaseFeeDenominator,
    89  		params.GovParamContract:          params.DefaultGovParamContract,
    90  		params.Kip82Ratio:                params.DefaultKip82Ratio,
    91  	}
    92  	if p, err := params.NewGovParamSetIntMap(defaultMap); err == nil {
    93  		e.defaultParams = p
    94  	} else {
    95  		logger.Crit("Error parsing initial ParamSet", "err", err)
    96  	}
    97  
    98  	// Setup subordinate engines
    99  	if doInit {
   100  		e.headerGov = NewGovernanceInitialize(config, db)
   101  	} else {
   102  		e.headerGov = NewGovernance(config, db)
   103  	}
   104  
   105  	e.contractGov = NewContractEngine(e.headerGov)
   106  
   107  	return e
   108  }
   109  
   110  // NewMixedEngine creates a governance engine using both contract-based and haeder-based gov.
   111  // Developers are encouraged to call this constructor in most cases.
   112  func NewMixedEngine(config *params.ChainConfig, db database.DBManager) *MixedEngine {
   113  	return newMixedEngine(config, db, true)
   114  }
   115  
   116  // NewMixedEngineNoInit creates a MixedEngine without initializing governance.
   117  func NewMixedEngineNoInit(config *params.ChainConfig, db database.DBManager) *MixedEngine {
   118  	return newMixedEngine(config, db, false)
   119  }
   120  
   121  func (e *MixedEngine) CurrentParams() *params.GovParamSet {
   122  	return e.currentParams
   123  }
   124  
   125  // EffectiveParams returns the parameter set used for generating the block `num`
   126  func (e *MixedEngine) EffectiveParams(num uint64) (*params.GovParamSet, error) {
   127  	var contractParams *params.GovParamSet
   128  	var err error
   129  
   130  	if e.config.IsKoreForkEnabled(new(big.Int).SetUint64(num)) {
   131  		contractParams, err = e.contractGov.EffectiveParams(num)
   132  		if err != nil {
   133  			logger.Error("contractGov.EffectiveParams() failed", "err", err)
   134  			return nil, err
   135  		}
   136  	} else {
   137  		contractParams = params.NewGovParamSet()
   138  	}
   139  
   140  	headerParams, err := e.headerGov.EffectiveParams(num)
   141  	if err != nil {
   142  		logger.Error("headerGov.EffectiveParams() failed", "err", err)
   143  		return nil, err
   144  	}
   145  
   146  	return e.assembleParams(headerParams, contractParams), nil
   147  }
   148  
   149  func (e *MixedEngine) UpdateParams(num uint64) error {
   150  	var contractParams *params.GovParamSet
   151  	numBigInt := big.NewInt(int64(num))
   152  
   153  	if e.config.IsKoreForkEnabled(numBigInt) {
   154  		if err := e.contractGov.UpdateParams(num); err != nil {
   155  			logger.Error("contractGov.UpdateParams(num) failed", "num", num, "err", err)
   156  			return err
   157  		}
   158  		contractParams = e.contractGov.CurrentParams()
   159  	} else {
   160  		contractParams = params.NewGovParamSet()
   161  	}
   162  
   163  	if err := e.headerGov.UpdateParams(num); err != nil {
   164  		logger.Error("headerGov.UpdateParams(num) failed", "num", num, "err", err)
   165  		return err
   166  	}
   167  
   168  	headerParams := e.headerGov.CurrentParams()
   169  
   170  	newParams := e.assembleParams(headerParams, contractParams)
   171  	e.handleParamUpdate(e.currentParams, newParams)
   172  
   173  	e.currentParams = newParams
   174  
   175  	return nil
   176  }
   177  
   178  func (e *MixedEngine) assembleParams(headerParams, contractParams *params.GovParamSet) *params.GovParamSet {
   179  	// Refer to the comments above `type MixedEngine` for assembly order
   180  	p := params.NewGovParamSet()
   181  	p = params.NewGovParamSetMerged(p, e.defaultParams)
   182  	p = params.NewGovParamSetMerged(p, e.initialParams)
   183  	p = params.NewGovParamSetMerged(p, headerParams)
   184  	p = params.NewGovParamSetMerged(p, contractParams)
   185  	return p
   186  }
   187  
   188  func (e *MixedEngine) handleParamUpdate(old, new *params.GovParamSet) {
   189  	// NOTE: key set must be the same, which is guaranteed at NewMixedEngine
   190  	for k, oldval := range old.IntMap() {
   191  		if newval := new.MustGet(k); oldval != newval {
   192  			switch k {
   193  			// config.Istanbul
   194  			case params.Epoch:
   195  				e.config.Istanbul.Epoch = new.Epoch()
   196  			case params.Policy:
   197  				e.config.Istanbul.ProposerPolicy = new.Policy()
   198  			case params.CommitteeSize:
   199  				e.config.Istanbul.SubGroupSize = new.CommitteeSize()
   200  			// config.Governance
   201  			case params.GoverningNode:
   202  				e.config.Governance.GoverningNode = new.GoverningNode()
   203  			case params.GovernanceMode:
   204  				e.config.Governance.GovernanceMode = new.GovernanceModeStr()
   205  			case params.GovParamContract:
   206  				e.config.Governance.GovParamContract = new.GovParamContract()
   207  			// config.Governance.Reward
   208  			case params.MintingAmount:
   209  				e.config.Governance.Reward.MintingAmount = new.MintingAmountBig()
   210  			case params.Ratio:
   211  				e.config.Governance.Reward.Ratio = new.Ratio()
   212  			case params.Kip82Ratio:
   213  				e.config.Governance.Reward.Kip82Ratio = new.Kip82Ratio()
   214  			case params.UseGiniCoeff:
   215  				e.config.Governance.Reward.UseGiniCoeff = new.UseGiniCoeff()
   216  			case params.DeferredTxFee:
   217  				e.config.Governance.Reward.DeferredTxFee = new.DeferredTxFee()
   218  			case params.MinimumStake:
   219  				e.config.Governance.Reward.MinimumStake = new.MinimumStakeBig()
   220  			case params.StakeUpdateInterval:
   221  				e.config.Governance.Reward.StakingUpdateInterval = new.StakeUpdateInterval()
   222  				params.SetStakingUpdateInterval(new.StakeUpdateInterval())
   223  			case params.ProposerRefreshInterval:
   224  				e.config.Governance.Reward.ProposerUpdateInterval = new.ProposerRefreshInterval()
   225  				params.SetProposerUpdateInterval(new.ProposerRefreshInterval())
   226  			// config.Governance.KIP17
   227  			case params.LowerBoundBaseFee:
   228  				e.config.Governance.KIP71.LowerBoundBaseFee = new.LowerBoundBaseFee()
   229  			case params.UpperBoundBaseFee:
   230  				e.config.Governance.KIP71.UpperBoundBaseFee = new.UpperBoundBaseFee()
   231  			case params.GasTarget:
   232  				e.config.Governance.KIP71.GasTarget = new.GasTarget()
   233  			case params.MaxBlockGasUsedForBaseFee:
   234  				e.config.Governance.KIP71.MaxBlockGasUsedForBaseFee = new.MaxBlockGasUsedForBaseFee()
   235  			case params.BaseFeeDenominator:
   236  				e.config.Governance.KIP71.BaseFeeDenominator = new.BaseFeeDenominator()
   237  			// others
   238  			case params.UnitPrice:
   239  				e.config.UnitPrice = new.UnitPrice()
   240  				if e.txpool != nil {
   241  					e.txpool.SetGasPrice(big.NewInt(0).SetUint64(new.UnitPrice()))
   242  				}
   243  			case params.DeriveShaImpl:
   244  				e.config.DeriveShaImpl = new.DeriveShaImpl()
   245  			}
   246  		}
   247  	}
   248  }
   249  
   250  func (e *MixedEngine) HeaderGov() HeaderEngine {
   251  	return e.headerGov
   252  }
   253  
   254  func (e *MixedEngine) ContractGov() ReaderEngine {
   255  	return e.contractGov
   256  }
   257  
   258  // Pass-through to HeaderEngine
   259  func (e *MixedEngine) AddVote(key string, val interface{}) bool {
   260  	return e.headerGov.AddVote(key, val)
   261  }
   262  
   263  func (e *MixedEngine) ValidateVote(vote *GovernanceVote) (*GovernanceVote, bool) {
   264  	return e.headerGov.ValidateVote(vote)
   265  }
   266  
   267  func (e *MixedEngine) CanWriteGovernanceState(num uint64) bool {
   268  	return e.headerGov.CanWriteGovernanceState(num)
   269  }
   270  
   271  func (e *MixedEngine) InitGovCache() {
   272  	e.headerGov.InitGovCache()
   273  }
   274  
   275  func (e *MixedEngine) InitLastGovStateBlkNum() {
   276  	e.headerGov.InitLastGovStateBlkNum()
   277  }
   278  
   279  func (e *MixedEngine) WriteGovernanceState(num uint64, isCheckpoint bool) error {
   280  	return e.headerGov.WriteGovernanceState(num, isCheckpoint)
   281  }
   282  
   283  func (e *MixedEngine) ReadGovernance(num uint64) (uint64, map[string]interface{}, error) {
   284  	return e.headerGov.ReadGovernance(num)
   285  }
   286  
   287  func (e *MixedEngine) WriteGovernance(num uint64, data GovernanceSet, delta GovernanceSet) error {
   288  	return e.headerGov.WriteGovernance(num, data, delta)
   289  }
   290  
   291  func (e *MixedEngine) GetEncodedVote(addr common.Address, number uint64) []byte {
   292  	return e.headerGov.GetEncodedVote(addr, number)
   293  }
   294  
   295  func (e *MixedEngine) GetGovernanceChange() map[string]interface{} {
   296  	return e.headerGov.GetGovernanceChange()
   297  }
   298  
   299  func (e *MixedEngine) VerifyGovernance(received []byte) error {
   300  	return e.headerGov.VerifyGovernance(received)
   301  }
   302  
   303  func (e *MixedEngine) ClearVotes(num uint64) {
   304  	e.headerGov.ClearVotes(num)
   305  }
   306  
   307  func (e *MixedEngine) WriteGovernanceForNextEpoch(number uint64, governance []byte) {
   308  	e.headerGov.WriteGovernanceForNextEpoch(number, governance)
   309  }
   310  
   311  func (e *MixedEngine) UpdateCurrentSet(num uint64) {
   312  	e.headerGov.UpdateCurrentSet(num)
   313  }
   314  
   315  func (e *MixedEngine) HandleGovernanceVote(
   316  	valset istanbul.ValidatorSet, votes []GovernanceVote, tally []GovernanceTallyItem,
   317  	header *types.Header, proposer common.Address, self common.Address, writable bool,
   318  ) (
   319  	istanbul.ValidatorSet, []GovernanceVote, []GovernanceTallyItem,
   320  ) {
   321  	return e.headerGov.HandleGovernanceVote(valset, votes, tally, header, proposer, self, writable)
   322  }
   323  
   324  func (e *MixedEngine) GetVoteMapCopy() map[string]VoteStatus {
   325  	return e.headerGov.GetVoteMapCopy()
   326  }
   327  
   328  func (e *MixedEngine) GetGovernanceTalliesCopy() []GovernanceTallyItem {
   329  	return e.headerGov.GetGovernanceTalliesCopy()
   330  }
   331  
   332  func (e *MixedEngine) CurrentSetCopy() map[string]interface{} {
   333  	return e.headerGov.CurrentSetCopy()
   334  }
   335  
   336  func (e *MixedEngine) PendingChanges() map[string]interface{} {
   337  	return e.headerGov.PendingChanges()
   338  }
   339  
   340  func (e *MixedEngine) Votes() []GovernanceVote {
   341  	return e.headerGov.Votes()
   342  }
   343  
   344  func (e *MixedEngine) IdxCache() []uint64 {
   345  	return e.headerGov.IdxCache()
   346  }
   347  
   348  func (e *MixedEngine) IdxCacheFromDb() []uint64 {
   349  	return e.headerGov.IdxCacheFromDb()
   350  }
   351  
   352  func (e *MixedEngine) NodeAddress() common.Address {
   353  	return e.headerGov.NodeAddress()
   354  }
   355  
   356  func (e *MixedEngine) TotalVotingPower() uint64 {
   357  	return e.headerGov.TotalVotingPower()
   358  }
   359  
   360  func (e *MixedEngine) MyVotingPower() uint64 {
   361  	return e.headerGov.MyVotingPower()
   362  }
   363  
   364  func (e *MixedEngine) BlockChain() blockChain {
   365  	return e.headerGov.BlockChain()
   366  }
   367  
   368  func (e *MixedEngine) DB() database.DBManager {
   369  	return e.headerGov.DB()
   370  }
   371  
   372  func (e *MixedEngine) SetNodeAddress(addr common.Address) {
   373  	e.headerGov.SetNodeAddress(addr)
   374  }
   375  
   376  func (e *MixedEngine) SetTotalVotingPower(t uint64) {
   377  	e.headerGov.SetTotalVotingPower(t)
   378  }
   379  
   380  func (e *MixedEngine) SetMyVotingPower(t uint64) {
   381  	e.headerGov.SetMyVotingPower(t)
   382  }
   383  
   384  func (e *MixedEngine) SetBlockchain(chain blockChain) {
   385  	e.blockchain = chain
   386  	e.headerGov.SetBlockchain(chain)
   387  }
   388  
   389  func (e *MixedEngine) SetTxPool(txpool txPool) {
   390  	e.txpool = txpool
   391  	e.headerGov.SetTxPool(txpool)
   392  }
   393  
   394  func (e *MixedEngine) GetTxPool() txPool {
   395  	return e.headerGov.GetTxPool()
   396  }