config.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package istanbul
  17. import (
  18. "math/big"
  19. "strings"
  20. "sync"
  21. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/common/math"
  24. "github.com/ethereum/go-ethereum/params"
  25. "github.com/naoina/toml"
  26. )
  27. type ProposerPolicyId uint64
  28. const (
  29. RoundRobin ProposerPolicyId = iota
  30. Sticky
  31. )
  32. // ProposerPolicy represents the Validator Proposer Policy
  33. type ProposerPolicy struct {
  34. Id ProposerPolicyId // Could be RoundRobin or Sticky
  35. By ValidatorSortByFunc // func that defines how the ValidatorSet should be sorted
  36. registry []ValidatorSet // Holds the ValidatorSet for a given block height
  37. registryMU *sync.Mutex // Mutex to lock access to changes to Registry
  38. }
  39. // NewRoundRobinProposerPolicy returns a RoundRobin ProposerPolicy with ValidatorSortByString as default sort function
  40. func NewRoundRobinProposerPolicy() *ProposerPolicy {
  41. return NewProposerPolicy(RoundRobin)
  42. }
  43. // NewStickyProposerPolicy return a Sticky ProposerPolicy with ValidatorSortByString as default sort function
  44. func NewStickyProposerPolicy() *ProposerPolicy {
  45. return NewProposerPolicy(Sticky)
  46. }
  47. func NewProposerPolicy(id ProposerPolicyId) *ProposerPolicy {
  48. return NewProposerPolicyByIdAndSortFunc(id, ValidatorSortByString())
  49. }
  50. func NewProposerPolicyByIdAndSortFunc(id ProposerPolicyId, by ValidatorSortByFunc) *ProposerPolicy {
  51. return &ProposerPolicy{Id: id, By: by, registryMU: new(sync.Mutex)}
  52. }
  53. type proposerPolicyToml struct {
  54. Id ProposerPolicyId
  55. }
  56. func (p *ProposerPolicy) MarshalTOML() (interface{}, error) {
  57. if p == nil {
  58. return nil, nil
  59. }
  60. pp := &proposerPolicyToml{Id: p.Id}
  61. data, err := toml.Marshal(pp)
  62. if err != nil {
  63. return nil, err
  64. }
  65. return string(data), nil
  66. }
  67. func (p *ProposerPolicy) UnmarshalTOML(decode func(interface{}) error) error {
  68. var innerToml string
  69. err := decode(&innerToml)
  70. if err != nil {
  71. return err
  72. }
  73. var pp proposerPolicyToml
  74. err = toml.Unmarshal([]byte(innerToml), &pp)
  75. if err != nil {
  76. return err
  77. }
  78. p.Id = pp.Id
  79. p.By = ValidatorSortByString()
  80. return nil
  81. }
  82. // Use sets the ValidatorSortByFunc for the given ProposerPolicy and sorts the validatorSets according to it
  83. func (p *ProposerPolicy) Use(v ValidatorSortByFunc) {
  84. p.By = v
  85. for _, validatorSet := range p.registry {
  86. validatorSet.SortValidators()
  87. }
  88. }
  89. // RegisterValidatorSet stores the given ValidatorSet in the policy registry
  90. func (p *ProposerPolicy) RegisterValidatorSet(valSet ValidatorSet) {
  91. p.registryMU.Lock()
  92. defer p.registryMU.Unlock()
  93. if len(p.registry) == 0 {
  94. p.registry = []ValidatorSet{valSet}
  95. } else {
  96. p.registry = append(p.registry, valSet)
  97. }
  98. }
  99. // ClearRegistry removes any ValidatorSet from the ProposerPolicy registry
  100. func (p *ProposerPolicy) ClearRegistry() {
  101. p.registryMU.Lock()
  102. defer p.registryMU.Unlock()
  103. p.registry = nil
  104. }
  105. type Config struct {
  106. RequestTimeout uint64 `toml:",omitempty"` // The timeout for each Istanbul round in milliseconds.
  107. BlockPeriod uint64 `toml:",omitempty"` // Default minimum difference between two consecutive block's timestamps in second
  108. EmptyBlockPeriod uint64 `toml:",omitempty"` // Default minimum difference between a block and empty block's timestamps in second
  109. ProposerPolicy *ProposerPolicy `toml:",omitempty"` // The policy for proposer selection
  110. Epoch uint64 `toml:",omitempty"` // The number of blocks after which to checkpoint and reset the pending votes
  111. Ceil2Nby3Block *big.Int `toml:",omitempty"` // Number of confirmations required to move from one state to next [2F + 1 to Ceil(2N/3)]
  112. AllowedFutureBlockTime uint64 `toml:",omitempty"` // Max time (in seconds) from current time allowed for blocks, before they're considered future blocks
  113. TestQBFTBlock *big.Int `toml:",omitempty"` // Fork block at which block confirmations are done using qbft consensus instead of ibft
  114. BeneficiaryMode *string `toml:",omitempty"` // Mode for setting the beneficiary, either: list, besu, validators (beneficiary list is the list of validators)
  115. BlockReward *math.HexOrDecimal256 `toml:",omitempty"` // Reward
  116. MiningBeneficiary *common.Address `toml:",omitempty"` // Wallet address that benefits at every new block (besu mode)
  117. ValidatorContract common.Address `toml:",omitempty"`
  118. Validators []common.Address `toml:",omitempty"`
  119. ValidatorSelectionMode *string `toml:",omitempty"`
  120. Client bind.ContractCaller `toml:",omitempty"`
  121. Transitions []params.Transition
  122. }
  123. var DefaultConfig = &Config{
  124. RequestTimeout: 10000,
  125. BlockPeriod: 5,
  126. EmptyBlockPeriod: 0,
  127. ProposerPolicy: NewRoundRobinProposerPolicy(),
  128. Epoch: 30000,
  129. Ceil2Nby3Block: big.NewInt(0),
  130. AllowedFutureBlockTime: 0,
  131. TestQBFTBlock: big.NewInt(0),
  132. }
  133. // QBFTBlockNumber returns the qbftBlock fork block number, returns -1 if qbftBlock is not defined
  134. func (c Config) QBFTBlockNumber() int64 {
  135. if c.TestQBFTBlock == nil {
  136. return -1
  137. }
  138. return c.TestQBFTBlock.Int64()
  139. }
  140. // IsQBFTConsensusAt checks if qbft consensus is enabled for the block height identified by the given header
  141. func (c *Config) IsQBFTConsensusAt(blockNumber *big.Int) bool {
  142. if c.TestQBFTBlock != nil {
  143. if c.TestQBFTBlock.Uint64() == 0 {
  144. return true
  145. }
  146. if blockNumber.Cmp(c.TestQBFTBlock) >= 0 {
  147. return true
  148. }
  149. }
  150. result := false
  151. if blockNumber == nil {
  152. blockNumber = big.NewInt(0)
  153. }
  154. c.getTransitionValue(blockNumber, func(t params.Transition) {
  155. if strings.EqualFold(t.Algorithm, params.QBFT) {
  156. result = true
  157. }
  158. })
  159. return result
  160. }
  161. func (c Config) GetConfig(blockNumber *big.Int) Config {
  162. newConfig := c
  163. c.getTransitionValue(blockNumber, func(transition params.Transition) {
  164. if transition.RequestTimeoutSeconds != 0 {
  165. newConfig.RequestTimeout = transition.RequestTimeoutSeconds
  166. }
  167. if transition.EpochLength != 0 {
  168. newConfig.Epoch = transition.EpochLength
  169. }
  170. if transition.BlockPeriodSeconds != 0 {
  171. newConfig.BlockPeriod = transition.BlockPeriodSeconds
  172. }
  173. if transition.EmptyBlockPeriodSeconds != nil {
  174. newConfig.EmptyBlockPeriod = *transition.EmptyBlockPeriodSeconds
  175. }
  176. if transition.BeneficiaryMode != nil {
  177. newConfig.BeneficiaryMode = transition.BeneficiaryMode
  178. }
  179. if transition.BlockReward != nil {
  180. newConfig.BlockReward = transition.BlockReward
  181. }
  182. if transition.MiningBeneficiary != nil {
  183. newConfig.MiningBeneficiary = transition.MiningBeneficiary
  184. }
  185. if transition.ValidatorSelectionMode != "" {
  186. newConfig.ValidatorSelectionMode = &transition.ValidatorSelectionMode
  187. }
  188. if transition.ValidatorContractAddress != (common.Address{}) {
  189. newConfig.ValidatorContract = transition.ValidatorContractAddress
  190. }
  191. if len(transition.Validators) > 0 {
  192. newConfig.Validators = transition.Validators
  193. }
  194. })
  195. return newConfig
  196. }
  197. func (c Config) GetValidatorContractAddress(blockNumber *big.Int) common.Address {
  198. validatorContractAddress := c.ValidatorContract
  199. c.getTransitionValue(blockNumber, func(transition params.Transition) {
  200. if (transition.ValidatorContractAddress != common.Address{}) {
  201. validatorContractAddress = transition.ValidatorContractAddress
  202. }
  203. })
  204. return validatorContractAddress
  205. }
  206. func (c Config) GetValidatorSelectionMode(blockNumber *big.Int) string {
  207. mode := params.BlockHeaderMode
  208. if c.ValidatorSelectionMode != nil {
  209. mode = *c.ValidatorSelectionMode
  210. }
  211. c.getTransitionValue(blockNumber, func(transition params.Transition) {
  212. if transition.ValidatorSelectionMode != "" {
  213. mode = transition.ValidatorSelectionMode
  214. }
  215. })
  216. return mode
  217. }
  218. func (c Config) GetValidatorsAt(blockNumber *big.Int) []common.Address {
  219. if blockNumber.Cmp(big.NewInt(0)) == 0 && len(c.Validators) > 0 {
  220. return c.Validators
  221. }
  222. if blockNumber != nil && c.Transitions != nil {
  223. for i := 0; i < len(c.Transitions) && c.Transitions[i].Block.Cmp(blockNumber) == 0; i++ {
  224. return c.Transitions[i].Validators
  225. }
  226. }
  227. //Note! empty means we will get the valset from previous block header which contains votes, validators etc
  228. return []common.Address{}
  229. }
  230. func (c Config) Get2FPlus1Enabled(blockNumber *big.Int) bool {
  231. twoFPlusOneEnabled := false
  232. c.getTransitionValue(blockNumber, func(transition params.Transition) {
  233. if transition.TwoFPlusOneEnabled != nil {
  234. twoFPlusOneEnabled = *transition.TwoFPlusOneEnabled
  235. }
  236. })
  237. return twoFPlusOneEnabled
  238. }
  239. func (c *Config) getTransitionValue(num *big.Int, callback func(transition params.Transition)) {
  240. if c != nil && num != nil && c.Transitions != nil {
  241. for i := 0; i < len(c.Transitions) && c.Transitions[i].Block.Cmp(num) <= 0; i++ {
  242. callback(c.Transitions[i])
  243. }
  244. }
  245. }