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 }