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 }