github.com/klaytn/klaytn@v1.12.1/params/governance_paramset_test.go (about) 1 package params 2 3 import ( 4 "encoding/json" 5 "math/big" 6 "testing" 7 8 "github.com/klaytn/klaytn/common" 9 "github.com/klaytn/klaytn/log" 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 func TestGovParamSet_ParseValue(t *testing.T) { 15 log.EnableLogForTest(log.LvlCrit, log.LvlWarn) 16 17 zeroAddr := common.HexToAddress("0x0000000000000000000000000000000000000000") 18 mintingAmount := "9600000000000000000" 19 mintingAmountBig, _ := new(big.Int).SetString(mintingAmount, 10) 20 21 testcases := []struct { 22 ty *govParamType 23 value interface{} 24 parsed interface{} // If ok, expected value. Ignored if not ok. 25 ok bool // Expected 'ok' 26 }{ 27 {govParamTypeGovMode, "none", "none", true}, 28 {govParamTypeGovMode, "single", "single", true}, 29 {govParamTypeGovMode, "ballot", "ballot", true}, 30 {govParamTypeGovMode, "asdf", nil, false}, 31 {govParamTypeGovMode, "", nil, false}, 32 {govParamTypeGovMode, 1, nil, false}, 33 34 {govParamTypeAddress, zeroAddr.Hex(), zeroAddr, true}, 35 {govParamTypeAddress, zeroAddr, zeroAddr, true}, 36 {govParamTypeAddress, 1, nil, false}, 37 38 {govParamTypeUint64, int(7), uint64(7), true}, 39 {govParamTypeUint64, uint(7), uint64(7), true}, 40 {govParamTypeUint64, uint64(7), uint64(7), true}, 41 {govParamTypeUint64, float64(1e9), uint64(1e9), true}, 42 {govParamTypeUint64, "123", nil, false}, 43 {govParamTypeUint64, -1, nil, false}, 44 {govParamTypeUint64, -12.0, nil, false}, 45 46 {govParamTypeBigInt, mintingAmount, mintingAmount, true}, 47 {govParamTypeBigInt, mintingAmountBig, mintingAmount, true}, 48 {govParamTypeBigInt, "123", "123", true}, 49 {govParamTypeBigInt, "-123", nil, false}, 50 {govParamTypeBigInt, "abc", nil, false}, 51 {govParamTypeBigInt, "", nil, false}, 52 53 {govParamTypeRatio, "100/0/0", "100/0/0", true}, 54 {govParamTypeRatio, "30/30/40", "30/30/40", true}, 55 {govParamTypeRatio, "10/20/30/40", nil, false}, 56 {govParamTypeRatio, "0/0/0", nil, false}, 57 {govParamTypeRatio, "1/2/3", nil, false}, 58 {govParamTypeRatio, "", nil, false}, 59 60 {govParamTypeBool, true, true, true}, 61 {govParamTypeBool, 0, nil, false}, 62 {govParamTypeBool, "", nil, false}, 63 } 64 65 for _, tc := range testcases { 66 parsed, ok := tc.ty.ParseValue(tc.value) 67 assert.Equal(t, tc.ok, ok) 68 if ok { 69 assert.Equal(t, tc.parsed, parsed) 70 } 71 } 72 } 73 74 func TestGovParamSet_ParseBytes(t *testing.T) { 75 zeroAddrHex := "0x0000000000000000000000000000000000000000" 76 zeroAddr := common.HexToAddress(zeroAddrHex) 77 mintingAmountStr := "9600000000000000000" 78 79 testcases := []struct { 80 ty *govParamType 81 bytes []byte 82 parsed interface{} // If ok, expected value. Ignored if not ok. 83 ok bool // Expected 'ok' 84 }{ 85 {govParamTypeGovMode, []byte("single"), "single", true}, 86 {govParamTypeGovMode, []byte(""), nil, false}, 87 88 {govParamTypeAddress, zeroAddr.Bytes(), zeroAddr, true}, 89 {govParamTypeAddress, []byte(zeroAddr.Hex()), nil, false}, 90 {govParamTypeAddress, []byte(""), nil, false}, 91 92 {govParamTypeUint64, []byte{0x12, 0x34}, uint64(0x1234), true}, 93 {govParamTypeUint64, []byte{}, uint64(0), true}, 94 {govParamTypeUint64, []byte{1, 2, 3, 4, 5, 6, 7, 8}, uint64(0x0102030405060708), true}, 95 {govParamTypeUint64, []byte{1, 1, 2, 3, 4, 5, 6, 7, 8}, nil, false}, 96 97 {govParamTypeBigInt, []byte(mintingAmountStr), mintingAmountStr, true}, 98 {govParamTypeBigInt, []byte("abcd"), nil, false}, 99 {govParamTypeBigInt, []byte(""), nil, false}, 100 101 {govParamTypeRatio, []byte("100/0/0"), "100/0/0", true}, 102 {govParamTypeRatio, []byte("10/20/30/40"), nil, false}, 103 {govParamTypeRatio, []byte(""), nil, false}, 104 105 {govParamTypeBool, []byte{0x01}, true, true}, 106 {govParamTypeBool, []byte{0x00}, false, true}, 107 {govParamTypeBool, []byte{0x99}, nil, false}, 108 {govParamTypeBool, []byte{}, nil, false}, 109 } 110 111 for _, tc := range testcases { 112 parsed, ok := tc.ty.ParseBytes(tc.bytes) 113 assert.Equal(t, tc.ok, ok) 114 if ok { 115 assert.Equal(t, tc.parsed, parsed) 116 } 117 } 118 } 119 120 func TestGovParamSet_GlobalMaps(t *testing.T) { 121 // Check that govParam* maps hold the same set of parameters. 122 123 assert.Equal(t, len(govParamTypes), len(govParamNames)) 124 for _, key := range govParamNames { 125 assert.NotNil(t, govParamTypes[key]) 126 } 127 } 128 129 func TestGovParamSet_Get(t *testing.T) { 130 num := uint64(123456) 131 p, _ := NewGovParamSetStrMap(map[string]interface{}{ 132 "istanbul.epoch": num, 133 }) 134 135 // Exists 136 v, ok := p.Get(Epoch) 137 assert.True(t, ok) 138 assert.Equal(t, num, v) 139 assert.Equal(t, num, p.MustGet(Epoch)) 140 141 // Not exists 142 v, ok = p.Get(CommitteeSize) 143 assert.False(t, ok) 144 assert.Nil(t, v) 145 } 146 147 func TestGovParamSet_Nominal(t *testing.T) { 148 c := CypressChainConfig.Copy() 149 c.Governance.KIP71 = &KIP71Config{ 150 LowerBoundBaseFee: 12340000, 151 UpperBoundBaseFee: 56780000, 152 GasTarget: 3000, 153 MaxBlockGasUsedForBaseFee: 6000, 154 BaseFeeDenominator: 100, 155 } 156 p, err := NewGovParamSetChainConfig(c) 157 assert.Nil(t, err) 158 159 assert.Equal(t, c.Istanbul.Epoch, p.Epoch()) 160 assert.Equal(t, c.Istanbul.ProposerPolicy, p.Policy()) 161 assert.Equal(t, c.Istanbul.SubGroupSize, p.CommitteeSize()) 162 assert.Equal(t, c.UnitPrice, p.UnitPrice()) 163 assert.Equal(t, c.DeriveShaImpl, p.DeriveShaImpl()) 164 assert.Equal(t, c.Governance.GovernanceMode, p.GovernanceModeStr()) 165 assert.Equal(t, c.Governance.GoverningNode, p.GoverningNode()) 166 assert.Equal(t, c.Governance.Reward.MintingAmount.String(), p.MintingAmountStr()) 167 assert.Equal(t, c.Governance.Reward.MintingAmount, p.MintingAmountBig()) 168 assert.Equal(t, c.Governance.Reward.Ratio, p.Ratio()) 169 assert.Equal(t, c.Governance.Reward.UseGiniCoeff, p.UseGiniCoeff()) 170 assert.Equal(t, c.Governance.Reward.DeferredTxFee, p.DeferredTxFee()) 171 assert.Equal(t, c.Governance.Reward.MinimumStake.String(), p.MinimumStakeStr()) 172 assert.Equal(t, c.Governance.Reward.MinimumStake, p.MinimumStakeBig()) 173 assert.Equal(t, c.Governance.Reward.StakingUpdateInterval, p.StakeUpdateInterval()) 174 assert.Equal(t, c.Governance.Reward.ProposerUpdateInterval, p.ProposerRefreshInterval()) 175 assert.Equal(t, c.Governance.KIP71.LowerBoundBaseFee, p.LowerBoundBaseFee()) 176 assert.Equal(t, c.Governance.KIP71.UpperBoundBaseFee, p.UpperBoundBaseFee()) 177 assert.Equal(t, c.Governance.KIP71.GasTarget, p.GasTarget()) 178 assert.Equal(t, c.Governance.KIP71.MaxBlockGasUsedForBaseFee, p.MaxBlockGasUsedForBaseFee()) 179 assert.Equal(t, c.Governance.KIP71.BaseFeeDenominator, p.BaseFeeDenominator()) 180 } 181 182 func TestGovParamSet_New(t *testing.T) { 183 p, err := NewGovParamSetStrMap(map[string]interface{}{ 184 "istanbul.epoch": 604800, 185 }) 186 assert.Nil(t, err) 187 v, ok := p.Get(Epoch) 188 assert.Equal(t, uint64(604800), v) 189 assert.True(t, ok) 190 191 p, err = NewGovParamSetIntMap(map[int]interface{}{ 192 Epoch: 604800, 193 }) 194 assert.Nil(t, err) 195 v, ok = p.Get(Epoch) 196 assert.Equal(t, uint64(604800), v) 197 assert.True(t, ok) 198 199 p, err = NewGovParamSetBytesMap(map[string][]byte{ 200 "istanbul.epoch": {0x12, 0x34}, 201 }) 202 assert.Nil(t, err) 203 v, ok = p.Get(Epoch) 204 assert.Equal(t, uint64(0x1234), v) 205 assert.True(t, ok) 206 207 c := CypressChainConfig 208 p, err = NewGovParamSetChainConfig(c) 209 assert.Nil(t, err) 210 v, ok = p.Get(Epoch) 211 assert.Equal(t, c.Istanbul.Epoch, v) 212 assert.True(t, ok) 213 214 p = NewGovParamSetBytesMapTolerant(map[string][]byte{ 215 "nonexistent-param1": {1}, 216 "nonexistent-param2": {2}, 217 "istanbul.epoch": {0x12, 0x34}, 218 }) 219 v, ok = p.Get(Epoch) 220 assert.Equal(t, uint64(0x1234), v) 221 assert.True(t, ok) 222 223 // Error cases 224 _, err = NewGovParamSetStrMap(map[string]interface{}{ 225 "istanbul.epoch": "asdf", 226 }) 227 assert.NotNil(t, err) 228 229 _, err = NewGovParamSetIntMap(map[int]interface{}{ 230 Epoch: "asdf", 231 }) 232 assert.NotNil(t, err) 233 234 _, err = NewGovParamSetBytesMap(map[string][]byte{ 235 "istanbul.epoch": {1, 1, 2, 3, 4, 5, 6, 7, 8}, 236 }) 237 assert.NotNil(t, err) 238 239 _, err = NewGovParamSetBytesMap(map[string][]byte{ 240 "nonexistent-param1": {1}, 241 "nonexistent-param2": {2}, 242 "istanbul.epoch": {3}, 243 }) 244 assert.NotNil(t, err) 245 } 246 247 func TestGovParamSet_Merged(t *testing.T) { 248 base, err := NewGovParamSetStrMap(map[string]interface{}{ 249 "istanbul.epoch": 123456, 250 "istanbul.committeesize": 77, 251 }) 252 assert.Nil(t, err) 253 254 update, err := NewGovParamSetStrMap(map[string]interface{}{ 255 "istanbul.committeesize": 99, 256 "istanbul.policy": 2, 257 }) 258 assert.Nil(t, err) 259 260 p := NewGovParamSetMerged(base, update) 261 262 // Was only in base 263 v, ok := p.Get(Epoch) 264 assert.Equal(t, uint64(123456), v) 265 assert.True(t, ok) 266 267 // Was only in update 268 v, ok = p.Get(Policy) 269 assert.Equal(t, uint64(2), v) 270 assert.True(t, ok) 271 272 // Was in both - prefers the value in update 273 v, ok = p.Get(CommitteeSize) 274 assert.Equal(t, uint64(99), v) 275 assert.True(t, ok) 276 } 277 278 func TestGovParamSet_RegressDb(t *testing.T) { 279 // MiscDB stores governance data as JSON strings. The value types can be 280 // slightly wrong during unmarshal because we unmarshal into interface{}. 281 // Namely, JSON integers can be converted to float64. 282 283 c := CypressChainConfig 284 p, err := NewGovParamSetChainConfig(c) 285 assert.Nil(t, err) 286 287 // Simulate database write then read 288 j, _ := json.Marshal(p.StrMap()) 289 var data map[string]interface{} 290 json.Unmarshal(j, &data) 291 292 pp, err := NewGovParamSetStrMap(data) 293 assert.Nil(t, err) 294 assert.Equal(t, p.items, pp.items) 295 } 296 297 func TestGovParamSet_GetMap(t *testing.T) { 298 c := CypressChainConfig 299 p, err := NewGovParamSetChainConfig(c) 300 assert.Nil(t, err) 301 302 sm := p.StrMap() 303 psm, err := NewGovParamSetStrMap(sm) 304 assert.Nil(t, err) 305 assert.Equal(t, p.items, psm.items) 306 307 im := p.IntMap() 308 pim, err := NewGovParamSetIntMap(im) 309 assert.Nil(t, err) 310 assert.Equal(t, p.items, pim.items) 311 } 312 313 func TestGovParamSet_ChainConfig(t *testing.T) { 314 log.EnableLogForTest(log.LvlCrit, log.LvlError) 315 testcases := []struct { 316 pset map[int]interface{} 317 expected *ChainConfig 318 }{ 319 // partial chainConfig 320 { 321 pset: map[int]interface{}{ 322 UnitPrice: 25e9, 323 Epoch: 30, 324 GoverningNode: common.HexToAddress("0x0000000000000000000000000000000000000400"), 325 MintingAmount: new(big.Int).SetUint64(9.6e18), 326 Ratio: "34/54/12", 327 UseGiniCoeff: true, 328 ProposerRefreshInterval: 3600, 329 LowerBoundBaseFee: 10000, 330 }, 331 expected: &ChainConfig{ 332 UnitPrice: 25e9, 333 Istanbul: &IstanbulConfig{ 334 Epoch: 30, 335 }, 336 Governance: &GovernanceConfig{ 337 GoverningNode: common.HexToAddress("0x0000000000000000000000000000000000000400"), 338 Reward: &RewardConfig{ 339 MintingAmount: new(big.Int).SetUint64(9.6e18), 340 Ratio: "34/54/12", 341 UseGiniCoeff: true, 342 ProposerUpdateInterval: 3600, 343 }, 344 KIP71: &KIP71Config{ 345 LowerBoundBaseFee: 10000, 346 }, 347 }, 348 }, 349 }, 350 // complete chainConfig 351 { 352 pset: map[int]interface{}{ 353 UnitPrice: 25e9, 354 Epoch: 30, 355 Policy: 1, 356 CommitteeSize: 27, 357 GoverningNode: common.HexToAddress("0x0000000000000000000000000000000000000400"), 358 GovernanceMode: "single", 359 MintingAmount: new(big.Int).SetUint64(9.6e18), 360 Ratio: "34/54/12", 361 UseGiniCoeff: true, 362 DeferredTxFee: true, 363 StakeUpdateInterval: 86400, 364 ProposerRefreshInterval: 3600, 365 MinimumStake: big.NewInt(5e6), 366 LowerBoundBaseFee: 25000000000, 367 UpperBoundBaseFee: 750000000000, 368 GasTarget: 30000000, 369 MaxBlockGasUsedForBaseFee: 60000000, 370 BaseFeeDenominator: 20, 371 Kip82Ratio: "20/80", 372 }, 373 expected: &ChainConfig{ 374 UnitPrice: 25e9, 375 Istanbul: &IstanbulConfig{ 376 Epoch: 30, 377 ProposerPolicy: 1, 378 SubGroupSize: 27, 379 }, 380 Governance: &GovernanceConfig{ 381 GoverningNode: common.HexToAddress("0x0000000000000000000000000000000000000400"), 382 GovernanceMode: "single", 383 Reward: &RewardConfig{ 384 MintingAmount: new(big.Int).SetUint64(9.6e18), 385 Ratio: "34/54/12", 386 Kip82Ratio: "20/80", 387 UseGiniCoeff: true, 388 DeferredTxFee: true, 389 StakingUpdateInterval: 86400, 390 ProposerUpdateInterval: 3600, 391 MinimumStake: big.NewInt(5e6), 392 }, 393 KIP71: &KIP71Config{ 394 LowerBoundBaseFee: 25000000000, 395 UpperBoundBaseFee: 750000000000, 396 GasTarget: 30000000, 397 MaxBlockGasUsedForBaseFee: 60000000, 398 BaseFeeDenominator: 20, 399 }, 400 }, 401 }, 402 }, 403 } 404 405 for _, tc := range testcases { 406 pset, err := NewGovParamSetIntMap(tc.pset) 407 require.Nil(t, err) 408 config := pset.ToChainConfig() 409 assert.Equal(t, tc.expected, config) 410 } 411 }