github.com/klaytn/klaytn@v1.10.2/governance/default.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 "encoding/binary" 21 "encoding/json" 22 "fmt" 23 "math/big" 24 "reflect" 25 "strings" 26 "sync" 27 "sync/atomic" 28 29 "github.com/klaytn/klaytn/common" 30 "github.com/klaytn/klaytn/log" 31 "github.com/klaytn/klaytn/params" 32 "github.com/klaytn/klaytn/rlp" 33 "github.com/klaytn/klaytn/storage/database" 34 "github.com/pkg/errors" 35 ) 36 37 var ( 38 ErrValueTypeMismatch = errors.New("Value's type mismatch") 39 ErrDecodeGovChange = errors.New("Failed to decode received governance changes") 40 ErrUnmarshalGovChange = errors.New("Failed to unmarshal received governance changes") 41 ErrVoteValueMismatch = errors.New("Received change mismatches with the value this node has!!") 42 ErrNotInitialized = errors.New("Cache not initialized") 43 ErrItemNotFound = errors.New("Failed to find governance item") 44 ErrItemNil = errors.New("Governance Item is nil") 45 ErrUnknownKey = errors.New("Governnace value of the given key not found") 46 ) 47 48 var ( 49 GovernanceKeyMap = map[string]int{ 50 "governance.governancemode": params.GovernanceMode, 51 "governance.governingnode": params.GoverningNode, 52 "governance.govparamcontract": params.GovParamContract, 53 "istanbul.epoch": params.Epoch, 54 "istanbul.policy": params.Policy, 55 "istanbul.committeesize": params.CommitteeSize, 56 "governance.unitprice": params.UnitPrice, 57 "governance.deriveshaimpl": params.DeriveShaImpl, 58 "kip71.lowerboundbasefee": params.LowerBoundBaseFee, 59 "kip71.gastarget": params.GasTarget, 60 "kip71.maxblockgasusedforbasefee": params.MaxBlockGasUsedForBaseFee, 61 "kip71.basefeedenominator": params.BaseFeeDenominator, 62 "kip71.upperboundbasefee": params.UpperBoundBaseFee, 63 "reward.mintingamount": params.MintingAmount, 64 "reward.ratio": params.Ratio, 65 "reward.kip82ratio": params.Kip82Ratio, 66 "reward.useginicoeff": params.UseGiniCoeff, 67 "reward.deferredtxfee": params.DeferredTxFee, 68 "reward.minimumstake": params.MinimumStake, 69 "reward.stakingupdateinterval": params.StakeUpdateInterval, 70 "reward.proposerupdateinterval": params.ProposerRefreshInterval, 71 "governance.addvalidator": params.AddValidator, 72 "governance.removevalidator": params.RemoveValidator, 73 "param.txgashumanreadable": params.ConstTxGasHumanReadable, 74 "istanbul.timeout": params.Timeout, 75 } 76 77 GovernanceForbiddenKeyMap = map[string]int{ 78 "istanbul.policy": params.Policy, 79 "reward.stakingupdateinterval": params.StakeUpdateInterval, 80 "reward.proposerupdateinterval": params.ProposerRefreshInterval, 81 } 82 83 GovernanceKeyMapReverse = map[int]string{ 84 params.GovernanceMode: "governance.governancemode", 85 params.GoverningNode: "governance.governingnode", 86 params.GovParamContract: "governance.govparamcontract", 87 params.Epoch: "istanbul.epoch", 88 params.CliqueEpoch: "clique.epoch", 89 params.Policy: "istanbul.policy", 90 params.CommitteeSize: "istanbul.committeesize", 91 params.UnitPrice: "governance.unitprice", 92 params.DeriveShaImpl: "governance.deriveshaimpl", 93 params.LowerBoundBaseFee: "kip71.lowerboundbasefee", 94 params.UpperBoundBaseFee: "kip71.upperboundbasefee", 95 params.GasTarget: "kip71.gastarget", 96 params.MaxBlockGasUsedForBaseFee: "kip71.maxblockgasusedforbasefee", 97 params.BaseFeeDenominator: "kip71.basefeedenominator", 98 params.MintingAmount: "reward.mintingamount", 99 params.Ratio: "reward.ratio", 100 params.UseGiniCoeff: "reward.useginicoeff", 101 params.DeferredTxFee: "reward.deferredtxfee", 102 params.MinimumStake: "reward.minimumstake", 103 params.StakeUpdateInterval: "reward.stakingupdateinterval", 104 params.ProposerRefreshInterval: "reward.proposerupdateinterval", 105 params.AddValidator: "governance.addvalidator", 106 params.RemoveValidator: "governance.removevalidator", 107 params.ConstTxGasHumanReadable: "param.txgashumanreadable", 108 params.Timeout: "istanbul.timeout", 109 params.Kip82Ratio: "reward.kip82ratio", 110 } 111 112 ProposerPolicyMap = map[string]int{ 113 "roundrobin": params.RoundRobin, 114 "sticky": params.Sticky, 115 "weightedrandom": params.WeightedRandom, 116 } 117 118 ProposerPolicyMapReverse = map[int]string{ 119 params.RoundRobin: "roundrobin", 120 params.Sticky: "sticky", 121 params.WeightedRandom: "weightedrandom", 122 } 123 124 GovernanceModeMap = map[string]int{ 125 "none": params.GovernanceMode_None, 126 "single": params.GovernanceMode_Single, 127 "ballot": params.GovernanceMode_Ballot, 128 } 129 ) 130 131 var logger = log.NewModuleLogger(log.Governance) 132 133 // GovernanceSet contains an item set for governance 134 type GovernanceSet struct { 135 items map[string]interface{} 136 mu *sync.RWMutex 137 } 138 139 // GovernanceVote represents vote information given from istanbul.vote() 140 type GovernanceVote struct { 141 Validator common.Address `json:"validator"` 142 Key string `json:"key"` 143 Value interface{} `json:"value"` 144 } 145 146 // GovernanceTallyItem represents a tally for each governance item 147 type GovernanceTallyItem struct { 148 Key string `json:"key"` 149 Value interface{} `json:"value"` 150 Votes uint64 `json:"votes"` 151 } 152 153 type GovernanceTallyList struct { 154 items []GovernanceTallyItem 155 mu *sync.RWMutex 156 } 157 type GovernanceVotes struct { 158 items []GovernanceVote 159 mu *sync.RWMutex 160 } 161 162 type VoteStatus struct { 163 Value interface{} `json:"value"` 164 Casted bool `json:"casted"` 165 Num uint64 `json:"num"` 166 } 167 168 type VoteMap struct { 169 items map[string]VoteStatus 170 mu *sync.RWMutex 171 } 172 173 // txPool is an interface for blockchain.TxPool used in governance package. 174 type txPool interface { 175 SetGasPrice(price *big.Int) 176 GasPrice() *big.Int 177 } 178 179 type Governance struct { 180 ChainConfig *params.ChainConfig // Only exists to keep DB backward compatibility in WriteGovernanceState() 181 // Map used to keep multiple types of votes 182 voteMap VoteMap 183 184 nodeAddress atomic.Value // common.Address 185 totalVotingPower uint64 186 votingPower uint64 187 188 GovernanceVotes GovernanceVotes 189 GovernanceTallies GovernanceTallyList 190 191 db database.DBManager 192 itemCache common.Cache 193 idxCache []uint64 // elements should be in ascending order 194 idxCacheLock *sync.RWMutex 195 196 // The block number when current governance information was changed 197 actualGovernanceBlock atomic.Value // uint64 198 199 // The last block number at governance state was stored (used not to replay old votes) 200 lastGovernanceStateBlock uint64 201 202 currentSet GovernanceSet 203 changeSet GovernanceSet 204 currentParams *params.GovParamSet // equals to currentSet 205 initialParams *params.GovParamSet // equals to initial ChainConfig 206 207 TxPool txPool 208 209 blockChain blockChain 210 } 211 212 func NewVoteMap() VoteMap { 213 return VoteMap{ 214 items: make(map[string]VoteStatus), 215 mu: new(sync.RWMutex), 216 } 217 } 218 219 func NewGovernanceTallies() GovernanceTallyList { 220 return GovernanceTallyList{ 221 items: []GovernanceTallyItem{}, 222 mu: new(sync.RWMutex), 223 } 224 } 225 226 func NewGovernanceVotes() GovernanceVotes { 227 return GovernanceVotes{ 228 items: []GovernanceVote{}, 229 mu: new(sync.RWMutex), 230 } 231 } 232 233 func (gt *GovernanceTallyList) Clear() { 234 gt.mu.Lock() 235 defer gt.mu.Unlock() 236 237 gt.items = make([]GovernanceTallyItem, 0) 238 } 239 240 func (vl *VoteMap) Copy() map[string]VoteStatus { 241 vl.mu.RLock() 242 defer vl.mu.RUnlock() 243 244 ret := make(map[string]VoteStatus) 245 for k, v := range vl.items { 246 ret[k] = v 247 } 248 249 return ret 250 } 251 252 func (vl *VoteMap) GetValue(key string) VoteStatus { 253 vl.mu.RLock() 254 defer vl.mu.RUnlock() 255 256 return vl.items[key] 257 } 258 259 func (vl *VoteMap) SetValue(key string, val VoteStatus) { 260 vl.mu.Lock() 261 defer vl.mu.Unlock() 262 263 vl.items[key] = val 264 } 265 266 func (vl *VoteMap) Import(src map[string]VoteStatus) { 267 vl.mu.Lock() 268 defer vl.mu.Unlock() 269 270 for k, v := range src { 271 vl.items[k] = v 272 } 273 } 274 275 func (vl *VoteMap) Clear() { 276 vl.mu.Lock() 277 defer vl.mu.Unlock() 278 279 // TODO-Governance if vote is not casted, it can remain forever. So, it would be better to add expiration. 280 newItems := make(map[string]VoteStatus) 281 for k, v := range vl.items { 282 if !v.Casted { 283 newItems[k] = v 284 } 285 } 286 vl.items = newItems 287 } 288 289 func (vl *VoteMap) Size() int { 290 vl.mu.RLock() 291 defer vl.mu.RUnlock() 292 293 return len(vl.items) 294 } 295 296 func (gt *GovernanceTallyList) Copy() []GovernanceTallyItem { 297 gt.mu.RLock() 298 defer gt.mu.RUnlock() 299 300 ret := make([]GovernanceTallyItem, len(gt.items)) 301 copy(ret, gt.items) 302 303 return ret 304 } 305 306 func (gt *GovernanceTallyList) Import(src []GovernanceTallyItem) { 307 gt.mu.Lock() 308 defer gt.mu.Unlock() 309 310 gt.items = make([]GovernanceTallyItem, len(src)) 311 copy(gt.items, src) 312 } 313 314 func (gv *GovernanceVotes) Clear() { 315 gv.mu.Lock() 316 defer gv.mu.Unlock() 317 gv.items = make([]GovernanceVote, 0) 318 } 319 320 func (gv *GovernanceVotes) Copy() []GovernanceVote { 321 gv.mu.RLock() 322 defer gv.mu.RUnlock() 323 324 ret := make([]GovernanceVote, len(gv.items)) 325 copy(ret, gv.items) 326 327 return ret 328 } 329 330 func (gv *GovernanceVotes) Import(src []GovernanceVote) { 331 gv.mu.Lock() 332 defer gv.mu.Unlock() 333 334 gv.items = make([]GovernanceVote, len(src)) 335 copy(gv.items, src) 336 } 337 338 func NewGovernanceSet() GovernanceSet { 339 return GovernanceSet{ 340 items: map[string]interface{}{}, 341 mu: new(sync.RWMutex), 342 } 343 } 344 345 func (gs *GovernanceSet) Clear() { 346 gs.mu.Lock() 347 defer gs.mu.Unlock() 348 349 gs.items = make(map[string]interface{}) 350 } 351 352 func (gs *GovernanceSet) SetValue(itemType int, value interface{}) error { 353 gs.mu.Lock() 354 defer gs.mu.Unlock() 355 356 key := GovernanceKeyMapReverse[itemType] 357 if !checkValueType(value, GovernanceItems[itemType].t) { 358 return ErrValueTypeMismatch 359 } 360 gs.items[key] = value 361 return nil 362 } 363 364 func (gs *GovernanceSet) GetValue(key int) (interface{}, bool) { 365 sKey, ok := GovernanceKeyMapReverse[key] 366 if !ok { 367 return nil, false 368 } 369 370 gs.mu.RLock() 371 defer gs.mu.RUnlock() 372 ret, ok := gs.items[sKey] 373 return ret, ok 374 } 375 376 func (gs *GovernanceSet) RemoveItem(key string) { 377 gs.mu.Lock() 378 defer gs.mu.Unlock() 379 380 delete(gs.items, key) 381 } 382 383 func (gs *GovernanceSet) Size() int { 384 gs.mu.RLock() 385 defer gs.mu.RUnlock() 386 387 return len(gs.items) 388 } 389 390 func (gs *GovernanceSet) Import(src map[string]interface{}) { 391 gs.mu.Lock() 392 defer gs.mu.Unlock() 393 394 gs.items = make(map[string]interface{}) 395 for k, v := range src { 396 gs.items[k] = v 397 } 398 } 399 400 func (gs *GovernanceSet) Items() map[string]interface{} { 401 gs.mu.Lock() 402 defer gs.mu.Unlock() 403 404 ret := make(map[string]interface{}) 405 for k, v := range gs.items { 406 ret[k] = v 407 } 408 return ret 409 } 410 411 func (gs *GovernanceSet) Merge(change map[string]interface{}) { 412 gs.mu.Lock() 413 defer gs.mu.Unlock() 414 415 for k, v := range change { 416 gs.items[k] = v 417 } 418 } 419 420 // NewGovernance creates Governance with the given configuration. 421 func NewGovernance(chainConfig *params.ChainConfig, dbm database.DBManager) *Governance { 422 return &Governance{ 423 ChainConfig: chainConfig, 424 voteMap: NewVoteMap(), 425 db: dbm, 426 itemCache: newGovernanceCache(), 427 currentSet: NewGovernanceSet(), 428 changeSet: NewGovernanceSet(), 429 currentParams: params.NewGovParamSet(), 430 initialParams: params.NewGovParamSet(), 431 lastGovernanceStateBlock: 0, 432 GovernanceTallies: NewGovernanceTallies(), 433 GovernanceVotes: NewGovernanceVotes(), 434 idxCacheLock: new(sync.RWMutex), 435 } 436 } 437 438 // NewGovernanceInitialize creates Governance with the given configuration and read governance state from DB. 439 // If any items are not stored in DB, it stores governance items of the genesis block to DB. 440 func NewGovernanceInitialize(chainConfig *params.ChainConfig, dbm database.DBManager) *Governance { 441 ret := NewGovernance(chainConfig, dbm) 442 // nil is for testing or simple function usage 443 if dbm != nil { 444 ret.ReadGovernanceState() 445 if err := ret.initializeCache(chainConfig); err != nil { 446 // If this is the first time to run, store governance information for genesis block on database 447 cfg := GetGovernanceItemsFromChainConfig(chainConfig) 448 if err := ret.WriteGovernance(0, cfg, NewGovernanceSet()); err != nil { 449 logger.Crit("Error in writing governance information", "err", err) 450 } 451 // If failed again after writing governance, stop booting up 452 if err = ret.initializeCache(chainConfig); err != nil { 453 logger.Crit("No governance cache index found in a database", "err", err) 454 } 455 } 456 } 457 return ret 458 } 459 460 func (g *Governance) updateGovernanceParams() { 461 params.SetStakingUpdateInterval(g.stakingUpdateInterval()) 462 params.SetProposerUpdateInterval(g.proposerUpdateInterval()) 463 464 // NOTE: HumanReadable related functions are inactivated now 465 if txGasHumanReadable, ok := g.currentSet.GetValue(params.ConstTxGasHumanReadable); ok { 466 params.TxGasHumanReadable = txGasHumanReadable.(uint64) 467 } 468 } 469 470 func (g *Governance) SetNodeAddress(addr common.Address) { 471 g.nodeAddress.Store(addr) 472 } 473 474 func (g *Governance) SetTotalVotingPower(t uint64) { 475 atomic.StoreUint64(&g.totalVotingPower, t) 476 } 477 478 func (g *Governance) SetMyVotingPower(t uint64) { 479 atomic.StoreUint64(&g.votingPower, t) 480 } 481 482 func (g *Governance) NodeAddress() common.Address { 483 return g.nodeAddress.Load().(common.Address) 484 } 485 486 func (g *Governance) TotalVotingPower() uint64 { 487 return atomic.LoadUint64(&g.totalVotingPower) 488 } 489 490 func (g *Governance) MyVotingPower() uint64 { 491 return atomic.LoadUint64(&g.votingPower) 492 } 493 494 func (gov *Governance) BlockChain() blockChain { 495 return gov.blockChain 496 } 497 498 func (gov *Governance) DB() database.DBManager { 499 return gov.db 500 } 501 502 func (g *Governance) GetEncodedVote(addr common.Address, number uint64) []byte { 503 // TODO-Klaytn-Governance Change this part to add all votes to the header at once 504 for key, val := range g.voteMap.Copy() { 505 if val.Casted == false { 506 vote := new(GovernanceVote) 507 vote.Validator = addr 508 vote.Key = key 509 vote.Value = val.Value 510 encoded, err := rlp.EncodeToBytes(vote) 511 if err != nil { 512 logger.Error("Failed to RLP Encode a vote", "vote", vote) 513 g.RemoveVote(key, val, number) 514 continue 515 } 516 return encoded 517 } 518 } 519 return nil 520 } 521 522 func (g *Governance) getKey(k string) string { 523 return strings.Trim(strings.ToLower(k), " ") 524 } 525 526 // RemoveVote removes a vote from the voteMap to prevent repetitive addition of same vote 527 func (g *Governance) RemoveVote(key string, value interface{}, number uint64) { 528 k := GovernanceKeyMap[key] 529 if isEqualValue(k, g.voteMap.GetValue(key).Value, value) { 530 g.voteMap.SetValue(key, VoteStatus{ 531 Value: value, 532 Casted: true, 533 Num: number, 534 }) 535 } 536 if g.CanWriteGovernanceState(number) { 537 g.WriteGovernanceState(number, false) 538 } 539 } 540 541 func (g *Governance) ClearVotes(num uint64) { 542 g.GovernanceVotes.Clear() 543 g.GovernanceTallies.Clear() 544 g.changeSet.Clear() 545 g.voteMap.Clear() 546 logger.Info("Governance votes are cleared", "num", num) 547 } 548 549 // ParseVoteValue parses vote.Value from []uint8, [][]uint8 to appropriate type 550 func (g *Governance) ParseVoteValue(gVote *GovernanceVote) (*GovernanceVote, error) { 551 var val interface{} 552 k, ok := GovernanceKeyMap[gVote.Key] 553 if !ok { 554 logger.Warn("Unknown key was given", "key", k) 555 return nil, ErrUnknownKey 556 } 557 558 switch k { 559 case params.GovernanceMode, params.MintingAmount, params.MinimumStake, params.Ratio, params.Kip82Ratio: 560 v, ok := gVote.Value.([]uint8) 561 if !ok { 562 return nil, ErrValueTypeMismatch 563 } 564 val = string(v) 565 case params.GoverningNode, params.GovParamContract: 566 v, ok := gVote.Value.([]uint8) 567 if !ok { 568 return nil, ErrValueTypeMismatch 569 } 570 val = common.BytesToAddress(v) 571 case params.AddValidator, params.RemoveValidator: 572 if v, ok := gVote.Value.([]uint8); ok { 573 // if value contains single address, gVote.Value type should be []uint8{} 574 val = common.BytesToAddress(v) 575 } else if addresses, ok := gVote.Value.([]interface{}); ok { 576 // if value contains multiple addresses, gVote.Value type should be [][]uint8{} 577 if len(addresses) == 0 { 578 return nil, ErrValueTypeMismatch 579 } 580 var nodeAddresses []common.Address 581 for _, item := range addresses { 582 if in, ok := item.([]uint8); !ok || len(in) != common.AddressLength { 583 return nil, ErrValueTypeMismatch 584 } 585 nodeAddresses = append(nodeAddresses, common.BytesToAddress(item.([]uint8))) 586 } 587 val = nodeAddresses 588 } else { 589 return nil, ErrValueTypeMismatch 590 } 591 case params.Epoch, params.CommitteeSize, params.UnitPrice, params.DeriveShaImpl, params.StakeUpdateInterval, 592 params.ProposerRefreshInterval, params.ConstTxGasHumanReadable, params.Policy, params.Timeout, 593 params.LowerBoundBaseFee, params.UpperBoundBaseFee, params.GasTarget, params.MaxBlockGasUsedForBaseFee, params.BaseFeeDenominator: 594 v, ok := gVote.Value.([]uint8) 595 if !ok { 596 return nil, ErrValueTypeMismatch 597 } 598 v = append(make([]byte, 8-len(v)), v...) 599 val = binary.BigEndian.Uint64(v) 600 case params.UseGiniCoeff, params.DeferredTxFee: 601 v, ok := gVote.Value.([]uint8) 602 if !ok { 603 return nil, ErrValueTypeMismatch 604 } 605 v = append(make([]byte, 8-len(v)), v...) 606 if binary.BigEndian.Uint64(v) != uint64(0) { 607 val = true 608 } else { 609 val = false 610 } 611 } 612 gVote.Value = val 613 return gVote, nil 614 } 615 616 func (gov *Governance) ReflectVotes(vote GovernanceVote) { 617 if ok := gov.updateChangeSet(vote); !ok { 618 logger.Error("Failed to reflect Governance Config", "Key", vote.Key, "Value", vote.Value) 619 } 620 } 621 622 func (gov *Governance) updateChangeSet(vote GovernanceVote) bool { 623 switch GovernanceKeyMap[vote.Key] { 624 case params.GoverningNode, params.GovParamContract: 625 gov.changeSet.SetValue(GovernanceKeyMap[vote.Key], vote.Value.(common.Address)) 626 return true 627 case params.GovernanceMode, params.Ratio, params.Kip82Ratio: 628 gov.changeSet.SetValue(GovernanceKeyMap[vote.Key], vote.Value.(string)) 629 return true 630 case params.Epoch, params.StakeUpdateInterval, params.ProposerRefreshInterval, params.CommitteeSize, 631 params.UnitPrice, params.DeriveShaImpl, params.ConstTxGasHumanReadable, params.Policy, params.Timeout, 632 params.LowerBoundBaseFee, params.UpperBoundBaseFee, params.GasTarget, params.MaxBlockGasUsedForBaseFee, params.BaseFeeDenominator: 633 gov.changeSet.SetValue(GovernanceKeyMap[vote.Key], vote.Value.(uint64)) 634 return true 635 case params.MintingAmount, params.MinimumStake: 636 gov.changeSet.SetValue(GovernanceKeyMap[vote.Key], vote.Value.(string)) 637 return true 638 case params.UseGiniCoeff, params.DeferredTxFee: 639 gov.changeSet.SetValue(GovernanceKeyMap[vote.Key], vote.Value.(bool)) 640 return true 641 default: 642 logger.Warn("Unknown key was given", "key", vote.Key) 643 } 644 return false 645 } 646 647 func CheckGenesisValues(c *params.ChainConfig) error { 648 gov := NewGovernanceInitialize(c, nil) 649 650 tstMap := map[string]interface{}{ 651 "istanbul.epoch": c.Istanbul.Epoch, 652 "istanbul.committeesize": c.Istanbul.SubGroupSize, 653 "istanbul.policy": uint64(c.Istanbul.ProposerPolicy), 654 "governance.governancemode": c.Governance.GovernanceMode, 655 "governance.governingnode": c.Governance.GoverningNode, 656 "governance.unitprice": c.UnitPrice, 657 "reward.ratio": c.Governance.Reward.Ratio, 658 "reward.useginicoeff": c.Governance.Reward.UseGiniCoeff, 659 "reward.deferredtxfee": c.Governance.Reward.DeferredTxFee, 660 "reward.mintingamount": c.Governance.Reward.MintingAmount.String(), 661 "reward.minimumstake": c.Governance.Reward.MinimumStake.String(), 662 "reward.stakingupdateinterval": c.Governance.Reward.StakingUpdateInterval, 663 "reward.proposerupdateinterval": c.Governance.Reward.ProposerUpdateInterval, 664 } 665 666 for k, v := range tstMap { 667 if _, ok := gov.ValidateVote(&GovernanceVote{Key: k, Value: v}); !ok { 668 return errors.New(k + " value is wrong") 669 } 670 } 671 return nil 672 } 673 674 func newGovernanceCache() common.Cache { 675 cache := common.NewCache(common.LRUConfig{CacheSize: params.GovernanceCacheLimit}) 676 return cache 677 } 678 679 // initializeCache reads governance item data from database and updates Governance.itemCache. 680 // It also initializes currentSet and actualGovernanceBlock according to head block number. 681 func (g *Governance) initializeCache(chainConfig *params.ChainConfig) error { 682 // get last n governance change block number 683 indices, err := g.db.ReadRecentGovernanceIdx(params.GovernanceIdxCacheLimit) 684 if err != nil { 685 return ErrNotInitialized 686 } 687 g.idxCache = indices 688 689 // Put governance items into the itemCache 690 for _, v := range indices { 691 if data, err := g.db.ReadGovernance(v); err == nil { 692 data = adjustDecodedSet(data) 693 g.itemCache.Add(getGovernanceCacheKey(v), data) 694 } else { 695 logger.Crit("Couldn't read governance cache from database. Check database consistency", "index", v, "err", err) 696 } 697 } 698 699 // g.db.ReadGovernance(N) returns the governance data stored in block 'N'. If the data is not exists, it simply returns an error. 700 // On the other hand, g.ReadGovernance(N) returns the governance data viewed by block 'N' and the block number at the time the governance data is stored. 701 // Since g.currentSet means the governance data viewed by the head block number of the node 702 // and g.actualGovernanceBlock means the block number at the time the governance data is stored, 703 // So those two variables are initialized by using the return values of the g.ReadGovernance(headBlockNum). 704 705 // head block number is used to get the appropriate g.currentSet and g.actualGovernanceBlock 706 headBlockNumber := uint64(0) 707 if headBlockHash := g.db.ReadHeadBlockHash(); !common.EmptyHash(headBlockHash) { 708 if num := g.db.ReadHeaderNumber(headBlockHash); num != nil { 709 headBlockNumber = *num 710 } else if headBlockHash := g.db.ReadHeadBlockBackupHash(); !common.EmptyHash(headBlockHash) { 711 if num := g.db.ReadHeaderNumber(headBlockHash); num != nil { 712 headBlockNumber = *num 713 } 714 } 715 } 716 newBlockNumber, newGovernanceSet, err := g.ReadGovernance(headBlockNumber) 717 if err != nil { 718 return err 719 } 720 // g.actualGovernanceBlock and currentSet is set 721 g.actualGovernanceBlock.Store(newBlockNumber) 722 g.currentSet.Import(newGovernanceSet) 723 724 // g.lastGovernanceStateBlock contains the last block number when voting data is included. 725 // we check the order between g.actualGovernanceBlock and g.lastGovernanceStateBlock, so make sure that voting is not missed. 726 governanceBlock, governanceStateBlock := g.actualGovernanceBlock.Load().(uint64), atomic.LoadUint64(&g.lastGovernanceStateBlock) 727 if governanceBlock >= governanceStateBlock { 728 ret, ok := g.itemCache.Get(getGovernanceCacheKey(governanceBlock)) 729 if !ok || ret == nil { 730 logger.Error("cannot get governance data at actualGovernanceBlock", "actualGovernanceBlock", governanceBlock) 731 return errors.New("Currentset initialization failed") 732 } 733 g.currentSet.Import(ret.(map[string]interface{})) 734 } 735 736 // Reflect CurrentSet -> g.initialParams 737 if pset, err := params.NewGovParamSetChainConfig(chainConfig); err == nil { 738 g.initialParams = pset 739 } else { 740 logger.Crit("Error parsing initial ChainConfig", "err", err) 741 } 742 // Reflect g.currentSet -> g.currentParams (for g.CurrentParams()) 743 // Outside initializeCache, istanbul.CreateSnapshot() will trigger UpdateParams(). 744 g.UpdateParams(headBlockNumber) 745 // Reflect g.currentSet -> global params in params/governance_params.go 746 // Outside initializeCache, GovernanceItems[].trigger will reflect changes to globals. 747 g.updateGovernanceParams() 748 749 return nil 750 } 751 752 // getGovernanceCache returns cached governance config as a byte slice 753 func (g *Governance) getGovernanceCache(num uint64) (map[string]interface{}, bool) { 754 cKey := getGovernanceCacheKey(num) 755 756 if ret, ok := g.itemCache.Get(cKey); ok && ret != nil { 757 return ret.(map[string]interface{}), true 758 } 759 return nil, false 760 } 761 762 func (g *Governance) addGovernanceCache(num uint64, data GovernanceSet) { 763 // Don't update cache if num (block number) is smaller than the biggest number of cached block number 764 g.idxCacheLock.Lock() 765 defer g.idxCacheLock.Unlock() 766 767 if len(g.idxCache) > 0 && num <= g.idxCache[len(g.idxCache)-1] { 768 logger.Error("The same or more recent governance index exist. Skip updating governance cache", 769 "newIdx", num, "govIdxes", g.idxCache) 770 return 771 } 772 cKey := getGovernanceCacheKey(num) 773 g.itemCache.Add(cKey, data.Items()) 774 775 g.idxCache = append(g.idxCache, num) 776 if len(g.idxCache) > params.GovernanceIdxCacheLimit { 777 g.idxCache = g.idxCache[len(g.idxCache)-params.GovernanceIdxCacheLimit:] 778 } 779 } 780 781 // getGovernanceCacheKey returns cache key of the given block number 782 func getGovernanceCacheKey(num uint64) common.GovernanceCacheKey { 783 v := fmt.Sprintf("%v", num) 784 return common.GovernanceCacheKey(params.GovernanceCachePrefix + "_" + v) 785 } 786 787 // Store new governance data on DB. This updates Governance cache too. 788 func (g *Governance) WriteGovernance(num uint64, data GovernanceSet, delta GovernanceSet) error { 789 g.idxCacheLock.RLock() 790 indices := make([]uint64, len(g.idxCache)) 791 copy(indices, g.idxCache) 792 g.idxCacheLock.RUnlock() 793 794 if len(indices) > 0 && num <= indices[len(indices)-1] { 795 logger.Error("The same or more recent governance index exist. Skip writing governance", 796 "newIdx", num, "govIdxes", indices) 797 return nil 798 } 799 800 new := NewGovernanceSet() 801 new.Import(data.Items()) 802 803 // merge delta into data 804 if delta.Size() > 0 { 805 new.Merge(delta.Items()) 806 } 807 g.addGovernanceCache(num, new) 808 return g.db.WriteGovernance(new.Items(), num) 809 } 810 811 func (g *Governance) searchCache(num uint64) (uint64, bool) { 812 g.idxCacheLock.RLock() 813 defer g.idxCacheLock.RUnlock() 814 815 for i := len(g.idxCache) - 1; i >= 0; i-- { 816 if g.idxCache[i] <= num { 817 return g.idxCache[i], true 818 } 819 } 820 return 0, false 821 } 822 823 func (g *Governance) ReadGovernance(num uint64) (uint64, map[string]interface{}, error) { 824 // epochWithFallback() falls back to Default before initializeCache() 825 epoch := g.epochWithFallback() 826 blockNum := CalcGovernanceInfoBlock(num, epoch) 827 828 // Check cache first 829 if gBlockNum, ok := g.searchCache(blockNum); ok { 830 if data, okay := g.getGovernanceCache(gBlockNum); okay { 831 return gBlockNum, data, nil 832 } 833 } 834 if g.db != nil { 835 bn, result, err := g.db.ReadGovernanceAtNumber(num, epoch) 836 result = adjustDecodedSet(result) 837 return bn, result, err 838 } else { 839 // For CI tests which don't have a database 840 return 0, nil, nil 841 } 842 } 843 844 func CalcGovernanceInfoBlock(num uint64, epoch uint64) uint64 { 845 governanceInfoBlock := num - (num % epoch) 846 if governanceInfoBlock >= epoch { 847 governanceInfoBlock -= epoch 848 } 849 return governanceInfoBlock 850 } 851 852 func (g *Governance) GetGovernanceChange() map[string]interface{} { 853 if g.changeSet.Size() > 0 { 854 return g.changeSet.Items() 855 } 856 return nil 857 } 858 859 // WriteGovernanceForNextEpoch creates governance items for next epoch and writes them to the database. 860 // The governance items on next epoch will be the given `governance` items applied on the top of past epoch items. 861 func (gov *Governance) WriteGovernanceForNextEpoch(number uint64, governance []byte) { 862 var epoch uint64 863 var ok bool 864 865 if epoch, ok = gov.GetGovernanceValue(params.Epoch).(uint64); !ok { 866 if epoch, ok = gov.GetGovernanceValue(params.CliqueEpoch).(uint64); !ok { 867 logger.Error("Couldn't find epoch from governance items") 868 return 869 } 870 } 871 872 // Store updated governance information if exist 873 if number%epoch == 0 { 874 if len(governance) > 0 { 875 tempData := []byte("") 876 tempItems := make(map[string]interface{}) 877 tempSet := NewGovernanceSet() 878 if err := rlp.DecodeBytes(governance, &tempData); err != nil { 879 logger.Error("Failed to decode governance data", "number", number, "err", err, "data", governance) 880 return 881 } 882 if err := json.Unmarshal(tempData, &tempItems); err != nil { 883 logger.Error("Failed to unmarshal governance data", "number", number, "err", err, "data", tempData) 884 return 885 886 } 887 tempItems = adjustDecodedSet(tempItems) 888 tempSet.Import(tempItems) 889 890 _, govItems, err := gov.ReadGovernance(number) 891 if err != nil { 892 logger.Error("Failed to read governance", "number", number, "err", err) 893 return 894 } 895 govSet := NewGovernanceSet() 896 govSet.Import(govItems) 897 898 // Store new governance items for next epoch to governance database 899 if err := gov.WriteGovernance(number, govSet, tempSet); err != nil { 900 logger.Crit("Failed to store new governance data", "number", number, "err", err) 901 } 902 } 903 } 904 } 905 906 func (gov *Governance) removeDuplicatedVote(vote *GovernanceVote, number uint64) { 907 gov.RemoveVote(vote.Key, vote.Value, number) 908 } 909 910 func (gov *Governance) UpdateCurrentSet(num uint64) { 911 newNumber, newGovernanceSet, _ := gov.ReadGovernance(num) 912 // Do the change only when the governance actually changed 913 if newGovernanceSet != nil && newNumber > gov.actualGovernanceBlock.Load().(uint64) { 914 gov.actualGovernanceBlock.Store(newNumber) 915 gov.currentSet.Import(newGovernanceSet) 916 gov.triggerChange(newGovernanceSet) 917 } 918 } 919 920 func (gov *Governance) triggerChange(src map[string]interface{}) { 921 for k, v := range src { 922 if f := GovernanceItems[GovernanceKeyMap[k]].trigger; f != nil { 923 f(gov, k, v) 924 } 925 } 926 } 927 928 func adjustDecodedSet(src map[string]interface{}) map[string]interface{} { 929 for k, v := range src { 930 x := reflect.ValueOf(v) 931 if x.Kind() == reflect.Float64 { 932 src[k] = uint64(v.(float64)) 933 } 934 if GovernanceKeyMap[k] == params.GoverningNode || 935 GovernanceKeyMap[k] == params.GovParamContract { 936 if reflect.TypeOf(v) == stringT { 937 src[k] = common.HexToAddress(v.(string)) 938 } else { 939 src[k] = v 940 } 941 } 942 } 943 return src 944 } 945 946 func (gov *Governance) GetGovernanceValue(key int) interface{} { 947 if v, ok := gov.currentSet.GetValue(key); !ok { 948 return nil 949 } else { 950 return v 951 } 952 } 953 954 func (gov *Governance) VerifyGovernance(received []byte) error { 955 change := []byte{} 956 if rlp.DecodeBytes(received, &change) != nil { 957 return ErrDecodeGovChange 958 } 959 960 rChangeSet := make(map[string]interface{}) 961 if json.Unmarshal(change, &rChangeSet) != nil { 962 return ErrUnmarshalGovChange 963 } 964 rChangeSet = adjustDecodedSet(rChangeSet) 965 966 if len(rChangeSet) != gov.changeSet.Size() { 967 logger.Error("Verification Error", "len(receivedChangeSet)", len(rChangeSet), "len(changeSet)", gov.changeSet.Size()) 968 } 969 970 for k, v := range rChangeSet { 971 if GovernanceKeyMap[k] == params.GoverningNode || 972 GovernanceKeyMap[k] == params.GovParamContract { 973 if reflect.TypeOf(v) == stringT { 974 v = common.HexToAddress(v.(string)) 975 } 976 } 977 978 have, _ := gov.changeSet.GetValue(GovernanceKeyMap[k]) 979 if have != v { 980 logger.Error("Verification Error", "key", k, "received", rChangeSet[k], "have", have, "receivedType", reflect.TypeOf(rChangeSet[k]), "haveType", reflect.TypeOf(have)) 981 return ErrVoteValueMismatch 982 } 983 } 984 return nil 985 } 986 987 type governanceJSON struct { 988 BlockNumber uint64 `json:"blockNumber"` 989 ChainConfig *params.ChainConfig `json:"chainConfig"` 990 VoteMap map[string]VoteStatus `json:"voteMap"` 991 NodeAddress common.Address `json:"nodeAddress"` 992 GovernanceVotes []GovernanceVote `json:"governanceVotes"` 993 GovernanceTally []GovernanceTallyItem `json:"governanceTally"` 994 CurrentSet map[string]interface{} `json:"currentSet"` 995 ChangeSet map[string]interface{} `json:"changeSet"` 996 } 997 998 func (gov *Governance) toJSON(num uint64) ([]byte, error) { 999 ret := &governanceJSON{ 1000 BlockNumber: num, 1001 ChainConfig: gov.ChainConfig, 1002 VoteMap: gov.voteMap.Copy(), 1003 NodeAddress: gov.nodeAddress.Load().(common.Address), 1004 GovernanceVotes: gov.GovernanceVotes.Copy(), 1005 GovernanceTally: gov.GovernanceTallies.Copy(), 1006 CurrentSet: gov.currentSet.Items(), 1007 ChangeSet: gov.changeSet.Items(), 1008 } 1009 j, _ := json.Marshal(ret) 1010 return j, nil 1011 } 1012 1013 func (gov *Governance) UnmarshalJSON(b []byte) error { 1014 var j governanceJSON 1015 if err := json.Unmarshal(b, &j); err != nil { 1016 return err 1017 } 1018 // gov.ChainConfig is to be updated in MixedEngine. Do not overwrite it here. 1019 gov.voteMap.Import(j.VoteMap) 1020 gov.nodeAddress.Store(j.NodeAddress) 1021 gov.GovernanceVotes.Import(j.GovernanceVotes) 1022 gov.GovernanceTallies.Import(j.GovernanceTally) 1023 gov.currentSet.Import(adjustDecodedSet(j.CurrentSet)) 1024 gov.changeSet.Import(adjustDecodedSet(j.ChangeSet)) 1025 atomic.StoreUint64(&gov.lastGovernanceStateBlock, j.BlockNumber) 1026 1027 return nil 1028 } 1029 1030 func (gov *Governance) CanWriteGovernanceState(num uint64) bool { 1031 if num <= atomic.LoadUint64(&gov.lastGovernanceStateBlock) { 1032 return false 1033 } 1034 return true 1035 } 1036 1037 func (gov *Governance) WriteGovernanceState(num uint64, isCheckpoint bool) error { 1038 if b, err := gov.toJSON(num); err != nil { 1039 logger.Error("Error in marshaling governance state", "err", err) 1040 return err 1041 } else { 1042 if err = gov.db.WriteGovernanceState(b); err != nil { 1043 logger.Error("Error in writing governance state", "err", err) 1044 return err 1045 } else { 1046 if isCheckpoint { 1047 atomic.StoreUint64(&gov.lastGovernanceStateBlock, num) 1048 } 1049 logger.Info("Successfully stored governance state", "num", num) 1050 return nil 1051 } 1052 } 1053 } 1054 1055 // ReadGovernanceState reads field values of the Governance struct from database. 1056 // It also updates params.stakingUpdateInterval and params.proposerUpdateInterval with the retrieved value. 1057 func (gov *Governance) ReadGovernanceState() { 1058 b, err := gov.db.ReadGovernanceState() 1059 if err != nil { 1060 logger.Info("No governance state found in a database") 1061 return 1062 } 1063 gov.UnmarshalJSON(b) 1064 gov.updateGovernanceParams() 1065 1066 logger.Info("Successfully loaded governance state from database", "blockNumber", atomic.LoadUint64(&gov.lastGovernanceStateBlock)) 1067 } 1068 1069 func (gov *Governance) SetBlockchain(bc blockChain) { 1070 gov.blockChain = bc 1071 } 1072 1073 func (gov *Governance) SetTxPool(txpool txPool) { 1074 gov.TxPool = txpool 1075 } 1076 1077 func (gov *Governance) GetTxPool() txPool { 1078 return gov.TxPool 1079 } 1080 1081 // GetGovernanceItemsFromChainConfig returns governance set 1082 // that is effective at the genesis block 1083 func GetGovernanceItemsFromChainConfig(config *params.ChainConfig) GovernanceSet { 1084 govSet := NewGovernanceSet() 1085 1086 // append to the return value `govSet` 1087 appendGovSet := func(govmap map[int]interface{}) { 1088 for k, v := range govmap { 1089 if err := govSet.SetValue(k, v); err != nil { 1090 writeFailLog(k, err) 1091 } 1092 } 1093 } 1094 1095 // original cypress params 1096 if config.Governance != nil { 1097 governance := config.Governance 1098 governanceMap := map[int]interface{}{ 1099 params.GovernanceMode: governance.GovernanceMode, 1100 params.GoverningNode: governance.GoverningNode, 1101 params.UnitPrice: config.UnitPrice, 1102 params.MintingAmount: governance.Reward.MintingAmount.String(), 1103 params.Ratio: governance.Reward.Ratio, 1104 params.UseGiniCoeff: governance.Reward.UseGiniCoeff, 1105 params.DeferredTxFee: governance.Reward.DeferredTxFee, 1106 params.MinimumStake: governance.Reward.MinimumStake.String(), 1107 params.StakeUpdateInterval: governance.Reward.StakingUpdateInterval, 1108 params.ProposerRefreshInterval: governance.Reward.ProposerUpdateInterval, 1109 } 1110 appendGovSet(governanceMap) 1111 } 1112 1113 if config.Istanbul != nil { 1114 istanbul := config.Istanbul 1115 istanbulMap := map[int]interface{}{ 1116 params.Epoch: istanbul.Epoch, 1117 params.Policy: istanbul.ProposerPolicy, 1118 params.CommitteeSize: istanbul.SubGroupSize, 1119 } 1120 appendGovSet(istanbulMap) 1121 } 1122 1123 // magma params 1124 if config.IsMagmaForkEnabled(common.Big0) && 1125 config.Governance.KIP71 != nil { 1126 kip71 := config.Governance.KIP71 1127 governanceMap := map[int]interface{}{ 1128 params.LowerBoundBaseFee: kip71.LowerBoundBaseFee, 1129 params.UpperBoundBaseFee: kip71.UpperBoundBaseFee, 1130 params.GasTarget: kip71.GasTarget, 1131 params.MaxBlockGasUsedForBaseFee: kip71.MaxBlockGasUsedForBaseFee, 1132 params.BaseFeeDenominator: kip71.BaseFeeDenominator, 1133 } 1134 appendGovSet(governanceMap) 1135 } 1136 1137 // kore params 1138 if config.IsKoreForkEnabled(common.Big0) && 1139 config.Governance != nil { 1140 governanceMap := map[int]interface{}{ 1141 params.DeriveShaImpl: uint64(config.DeriveShaImpl), // checkValueType expects uint64 1142 } 1143 if !common.EmptyAddress(config.Governance.GovParamContract) { 1144 governanceMap[params.GovParamContract] = config.Governance.GovParamContract 1145 } 1146 if config.Governance.Reward != nil && 1147 config.Governance.Reward.Kip82Ratio != "" { 1148 governanceMap[params.Kip82Ratio] = config.Governance.Reward.Kip82Ratio 1149 } 1150 appendGovSet(governanceMap) 1151 } 1152 1153 return govSet 1154 } 1155 1156 func writeFailLog(key int, err error) { 1157 msg := "Failed to set " + GovernanceKeyMapReverse[key] 1158 logger.Crit(msg, "err", err) 1159 } 1160 1161 func AddGovernanceCacheForTest(e HeaderEngine, num uint64, config *params.ChainConfig) { 1162 // addGovernanceCache only exists and relevant in *Governance. 1163 if g, ok := e.(*Governance); ok { 1164 data := GetGovernanceItemsFromChainConfig(config) 1165 g.addGovernanceCache(num, data) 1166 } 1167 } 1168 1169 func (gov *Governance) proposerUpdateInterval() uint64 { 1170 return gov.GetGovernanceValue(params.ProposerRefreshInterval).(uint64) 1171 } 1172 1173 func (gov *Governance) stakingUpdateInterval() uint64 { 1174 return gov.GetGovernanceValue(params.StakeUpdateInterval).(uint64) 1175 } 1176 1177 func (g *Governance) GetVoteMapCopy() map[string]VoteStatus { 1178 return g.voteMap.Copy() 1179 } 1180 1181 func (g *Governance) GetGovernanceTalliesCopy() []GovernanceTallyItem { 1182 return g.GovernanceTallies.Copy() 1183 } 1184 1185 func (gov *Governance) CurrentSetCopy() map[string]interface{} { 1186 return gov.currentSet.Items() 1187 } 1188 1189 func (gov *Governance) PendingChanges() map[string]interface{} { 1190 return gov.changeSet.Items() 1191 } 1192 1193 func (gov *Governance) Votes() []GovernanceVote { 1194 return gov.GovernanceVotes.Copy() 1195 } 1196 1197 func (gov *Governance) IdxCache() []uint64 { 1198 gov.idxCacheLock.RLock() 1199 defer gov.idxCacheLock.RUnlock() 1200 1201 copiedCache := make([]uint64, len(gov.idxCache)) 1202 copy(copiedCache, gov.idxCache) 1203 return copiedCache 1204 } 1205 1206 func (gov *Governance) IdxCacheFromDb() []uint64 { 1207 res, _ := gov.db.ReadRecentGovernanceIdx(0) 1208 return res 1209 } 1210 1211 // epochWithFallback returns the istanbul epoch. This function works even before loading any params 1212 // from database. We need epoch to load any param from database. 1213 func (gov *Governance) epochWithFallback() uint64 { 1214 // After UpdateParams() is called at least once, CurrentParams() should contain the Epoch 1215 if v, ok := gov.CurrentParams().Get(params.Epoch); ok { 1216 return v.(uint64) 1217 } 1218 // Otherwise after initializeCache() is called, initialParams should contain the Epoch 1219 if v, ok := gov.initialParams.Get(params.Epoch); ok { 1220 return v.(uint64) 1221 } 1222 1223 // Otherwise fallback to ChainConfig that is supplied to NewGovernance() 1224 if gov.ChainConfig.Istanbul != nil { 1225 return gov.ChainConfig.Istanbul.Epoch 1226 } 1227 // We shouldn't reach here because Governance is only relevant with Istanbul engine. 1228 logger.Crit("Failed to read governance. ChainConfig.Istanbul == nil") 1229 return params.DefaultEpoch // unreachable. just satisfying compiler. 1230 } 1231 1232 func (gov *Governance) CurrentParams() *params.GovParamSet { 1233 return gov.currentParams 1234 } 1235 1236 // EffectiveParams returns the parameter set used for generating the block `num` 1237 func (gov *Governance) EffectiveParams(num uint64) (*params.GovParamSet, error) { 1238 // TODO-Klaytn: Either handle epoch change, or permanently forbid epoch change. 1239 epoch := gov.epochWithFallback() 1240 1241 bignum := new(big.Int).SetUint64(num) 1242 1243 // Before Kore, ReadGovernance(num - 1) is used to generate block num 1244 if !gov.ChainConfig.IsKoreForkEnabled(bignum) && num != 0 { 1245 num -= 1 1246 } 1247 // Should be equivalent to Governance.ReadGovernance(), but without in-memory caches. 1248 // Not using in-memory caches to make it stateless, hence less error-prone. 1249 _, strMap, err := gov.db.ReadGovernanceAtNumber(num, epoch) 1250 if err != nil { 1251 logger.Error("ReadGovernanceAtNumber failed", "num", num, "err", err) 1252 return nil, err 1253 } 1254 pset, err := params.NewGovParamSetStrMap(strMap) 1255 if err != nil { 1256 logger.Error("NewGovParamSetStrMap failed", "num", num, "err", err) 1257 return nil, err 1258 } 1259 return pset, nil 1260 } 1261 1262 func (gov *Governance) UpdateParams(num uint64) error { 1263 pset, err := gov.EffectiveParams(num + 1) 1264 if err != nil { 1265 return err 1266 } 1267 gov.currentParams = pset 1268 return nil 1269 }