github.com/klaytn/klaytn@v1.12.1/governance/mixed_test.go (about)

     1  package governance
     2  
     3  import (
     4  	"math/big"
     5  	"testing"
     6  
     7  	"github.com/klaytn/klaytn/accounts/abi/bind"
     8  	"github.com/klaytn/klaytn/accounts/abi/bind/backends"
     9  	"github.com/klaytn/klaytn/common"
    10  	govcontract "github.com/klaytn/klaytn/contracts/gov"
    11  	"github.com/klaytn/klaytn/params"
    12  	"github.com/klaytn/klaytn/storage/database"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func newTestMixedEngine(t *testing.T, config *params.ChainConfig) (*MixedEngine, *bind.TransactOpts, *backends.SimulatedBackend, *govcontract.GovParam) {
    18  	config.IstanbulCompatibleBlock = common.Big0
    19  	config.LondonCompatibleBlock = common.Big0
    20  	config.EthTxTypeCompatibleBlock = common.Big0
    21  	config.MagmaCompatibleBlock = common.Big0
    22  	config.KoreCompatibleBlock = common.Big0
    23  
    24  	accounts, sim, addr, contract := prepareSimulatedContract(t)
    25  
    26  	config.Governance.GovParamContract = addr
    27  
    28  	db := database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB})
    29  	e := NewMixedEngine(config, db)
    30  	require.NotNil(t, e)
    31  	require.NotNil(t, e.headerGov)
    32  
    33  	e.SetBlockchain(sim.BlockChain())
    34  
    35  	return e, accounts[0], sim, contract
    36  }
    37  
    38  func newTestMixedEngineNoContractEngine(t *testing.T, config *params.ChainConfig) *MixedEngine {
    39  	// disable ContractEngine
    40  	config.KoreCompatibleBlock = new(big.Int).SetUint64(0xffffffff)
    41  
    42  	db := database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB})
    43  
    44  	e := NewMixedEngine(config, db)
    45  	headerGov := e.headerGov // to manipulate internal fields
    46  
    47  	require.NotNil(t, e)
    48  	require.NotNil(t, headerGov)
    49  
    50  	return e
    51  }
    52  
    53  // Without ContractGov, Check that
    54  //   - From a fresh MixedEngine instance, CurrentParams() and EffectiveParams(0) returns the
    55  //     initial config value.
    56  func TestMixedEngine_Header_New(t *testing.T) {
    57  	valueA := uint64(0x11)
    58  
    59  	config := getTestConfig()
    60  	config.Istanbul.SubGroupSize = valueA
    61  	e := newTestMixedEngineNoContractEngine(t, config)
    62  
    63  	// CurrentParams() should work even before explicitly calling UpdateParams().
    64  	// For instance in cn.New().
    65  	pset := e.CurrentParams()
    66  	assert.Equal(t, valueA, pset.CommitteeSize())
    67  
    68  	pset, err := e.EffectiveParams(0)
    69  	assert.Nil(t, err)
    70  	assert.Equal(t, valueA, pset.CommitteeSize())
    71  }
    72  
    73  // Without ContractGov, Check that
    74  // - after UpdateParams(), CurrentParams() returns the new value
    75  func TestMixedEngine_Header_Params(t *testing.T) {
    76  	valueA := uint64(0x11)
    77  	valueB := uint64(0x22)
    78  
    79  	config := getTestConfig()
    80  	config.Governance.KIP71.GasTarget = valueA
    81  	e := newTestMixedEngineNoContractEngine(t, config)
    82  	assert.Equal(t, valueA, e.CurrentParams().GasTarget())
    83  
    84  	items := e.CurrentParams().StrMap()
    85  	items["kip71.gastarget"] = valueB
    86  	gset := NewGovernanceSet()
    87  	gset.Import(items)
    88  	err := e.headerGov.WriteGovernance(e.CurrentParams().Epoch(), NewGovernanceSet(), gset)
    89  	assert.Nil(t, err)
    90  	err = e.UpdateParams(e.CurrentParams().Epoch() * 2)
    91  	assert.Nil(t, err)
    92  
    93  	assert.Equal(t, valueB, e.CurrentParams().GasTarget())
    94  	// check if config is updated as well
    95  	assert.Equal(t, valueB, config.Governance.KIP71.GasTarget)
    96  }
    97  
    98  // Before Kore hardfork (i.e., without ContractGov), check that
    99  // - after DB is written at [n - epoch], EffectiveParams(n+1) returns the new value
   100  // - EffectiveParams(n+1) == ReadGovernance(n)
   101  func TestMixedEngine_Header_ParamsAt(t *testing.T) {
   102  	valueA := uint64(0x11)
   103  	valueB := uint64(0x22)
   104  
   105  	config := getTestConfig()
   106  	config.Istanbul.Epoch = 30
   107  	config.Istanbul.SubGroupSize = valueA
   108  	e := newTestMixedEngineNoContractEngine(t, config)
   109  
   110  	// Write to database. Note that we must use gov.WriteGovernance(), not db.WriteGovernance()
   111  	// The reason is that gov.ReadGovernance() depends on the caches, and that
   112  	// gov.WriteGovernance() sets idxCache accordingly, whereas db.WriteGovernance don't
   113  	items := e.CurrentParams().StrMap()
   114  	items["istanbul.committeesize"] = valueB
   115  	gset := NewGovernanceSet()
   116  	gset.Import(items)
   117  	e.headerGov.WriteGovernance(30, NewGovernanceSet(), gset)
   118  
   119  	testcases := []struct {
   120  		num   uint64
   121  		value uint64
   122  	}{
   123  		{0, valueA},
   124  		{30, valueA},
   125  		{31, valueA},
   126  		{59, valueA},
   127  		{60, valueB},
   128  		{61, valueB},
   129  	}
   130  	for _, tc := range testcases {
   131  		// Check that e.EffectiveParams() == tc
   132  		pset, err := e.EffectiveParams(tc.num + 1)
   133  		assert.Nil(t, err)
   134  		assert.Equal(t, tc.value, pset.CommitteeSize())
   135  
   136  		// Check that headerGov.ReadGovernance() == tc
   137  		_, strMap, err := e.headerGov.ReadGovernance(tc.num)
   138  		assert.Nil(t, err)
   139  		pset, err = params.NewGovParamSetStrMap(strMap)
   140  		assert.Nil(t, err)
   141  		assert.Equal(t, tc.value, pset.CommitteeSize())
   142  	}
   143  }
   144  
   145  // TestMixedEngine_Params tests if CurrentParams() conforms to the fallback mechanism
   146  func TestMixedEngine_Params(t *testing.T) {
   147  	var (
   148  		valueA      = uint64(0xa)
   149  		valueB      = uint64(0xbb)
   150  		valueC      = uint64(0xcccccc)
   151  		valueCBytes = []byte{0xcc, 0xcc, 0xcc}
   152  	)
   153  	config := getTestConfig()
   154  	config.Governance.KIP71.GasTarget = valueA
   155  	config.Istanbul.Epoch = 4
   156  
   157  	// 1. fallback to ChainConfig because headerGov and contractGov don't have the param
   158  	e, owner, sim, contract := newTestMixedEngine(t, config)
   159  	require.Equal(t, valueA, e.CurrentParams().GasTarget(), "fallback to ChainConfig failed")
   160  
   161  	// 2. fallback to headerGov because contractGov doesn't have the param
   162  	delta := NewGovernanceSet()
   163  	delta.SetValue(params.GasTarget, valueB)
   164  	e.headerGov.WriteGovernance(4, e.headerGov.currentSet, delta)
   165  	for e.headerGov.blockChain.CurrentBlock().NumberU64() < 7 {
   166  		sim.Commit()
   167  	}
   168  	err := e.UpdateParams(e.headerGov.blockChain.CurrentBlock().NumberU64())
   169  	assert.Nil(t, err)
   170  	require.Equal(t, valueB, e.CurrentParams().GasTarget(), "fallback to headerGov failed")
   171  
   172  	// 3. use contractGov
   173  	_, err = contract.SetParamIn(owner, "kip71.gastarget", true, valueCBytes, big.NewInt(1))
   174  	assert.Nil(t, err)
   175  
   176  	sim.Commit() // mine SetParamIn
   177  
   178  	err = e.UpdateParams(e.headerGov.blockChain.CurrentBlock().NumberU64())
   179  	assert.Nil(t, err)
   180  	require.Equal(t, valueC, e.CurrentParams().GasTarget(), "fallback to contractGov failed")
   181  }
   182  
   183  // TestMixedEngine_ParamsAt tests if EffectiveParams() returns correct values
   184  // given headerBlock and contractBlock;
   185  //
   186  //	at headerBlock, params are inserted to DB via WriteGovernance()
   187  //	at contractBlock, params are inserted to GovParam via SetParamIn() contract call.
   188  //
   189  // valueA is set in ChainConfig
   190  // valueB is set in DB
   191  // valueC is set in GovParam contract
   192  //
   193  //	chainConfig     headerBlock    contractBlock       now
   194  //
   195  // Block |---------------|--------------|---------------|
   196  //
   197  // ............valueA          valueB         valueC
   198  func TestMixedEngine_ParamsAt(t *testing.T) {
   199  	var (
   200  		name        = "kip71.gastarget"
   201  		valueA      = uint64(0xa)
   202  		valueB      = uint64(0xbb)
   203  		valueC      = uint64(0xcccccc)
   204  		valueCBytes = []byte{0xcc, 0xcc, 0xcc}
   205  	)
   206  
   207  	config := getTestConfig()
   208  	config.Istanbul.Epoch = 1
   209  
   210  	// set initial value
   211  	config.Governance.KIP71.GasTarget = valueA
   212  
   213  	e, owner, sim, contract := newTestMixedEngine(t, config)
   214  
   215  	// write minimal params for test to headerGov
   216  	// note that mainnet will have all parameters in the headerGov db
   217  	headerBlock := sim.BlockChain().CurrentBlock().NumberU64()
   218  	e.headerGov.db.WriteGovernance(map[string]interface{}{
   219  		name:                          valueB,
   220  		"governance.govparamcontract": config.Governance.GovParamContract,
   221  	}, headerBlock)
   222  	err := e.UpdateParams(headerBlock)
   223  	assert.Nil(t, err)
   224  
   225  	// forward a few blocks
   226  	for i := 0; i < 3; i++ {
   227  		sim.Commit()
   228  	}
   229  
   230  	// write to contractGov
   231  	_, err = contract.SetParamIn(owner, name, true, valueCBytes, big.NewInt(1))
   232  	assert.Nil(t, err)
   233  
   234  	sim.Commit() // mine SetParamIn
   235  	contractBlock := sim.BlockChain().CurrentHeader().Number.Uint64()
   236  
   237  	// forward a few blocks
   238  	for i := 0; i < 3; i++ {
   239  		sim.Commit()
   240  	}
   241  
   242  	now := sim.BlockChain().CurrentHeader().Number.Uint64()
   243  	for i := uint64(0); i < now; i++ {
   244  		pset, err := e.EffectiveParams(i)
   245  		assert.Nil(t, err)
   246  
   247  		val, ok := pset.Get(params.GasTarget)
   248  		assert.True(t, ok)
   249  
   250  		var expected uint64
   251  
   252  		switch {
   253  		case i <= headerBlock:
   254  			expected = valueA
   255  		case i <= contractBlock:
   256  			expected = valueB
   257  		default:
   258  			expected = valueC
   259  		}
   260  
   261  		assert.Equal(t, expected, val,
   262  			"EffectiveParams(%d) failed (headerBlock=%d contractBlock=%d)",
   263  			i, headerBlock, contractBlock)
   264  	}
   265  }