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  }