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

     1  // Copyright 2022 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package governance
    18  
    19  import (
    20  	"math/big"
    21  	"testing"
    22  
    23  	"github.com/klaytn/klaytn/accounts/abi/bind"
    24  	"github.com/klaytn/klaytn/accounts/abi/bind/backends"
    25  	"github.com/klaytn/klaytn/blockchain"
    26  	"github.com/klaytn/klaytn/blockchain/types"
    27  	"github.com/klaytn/klaytn/common"
    28  	govcontract "github.com/klaytn/klaytn/contracts/gov"
    29  	"github.com/klaytn/klaytn/crypto"
    30  	"github.com/klaytn/klaytn/params"
    31  	"github.com/klaytn/klaytn/storage/database"
    32  	"github.com/stretchr/testify/assert"
    33  	"github.com/stretchr/testify/require"
    34  )
    35  
    36  func prepareSimulatedContract(t *testing.T) ([]*bind.TransactOpts, *backends.SimulatedBackend, common.Address, *govcontract.GovParam) {
    37  	// Create accounts and simulated blockchain
    38  	accounts := []*bind.TransactOpts{}
    39  	alloc := blockchain.GenesisAlloc{}
    40  	for i := 0; i < 1; i++ {
    41  		key, _ := crypto.GenerateKey()
    42  		account := bind.NewKeyedTransactor(key)
    43  		account.GasLimit = 10000000
    44  		accounts = append(accounts, account)
    45  		alloc[account.From] = blockchain.GenesisAccount{Balance: big.NewInt(params.KLAY)}
    46  	}
    47  	config := &params.ChainConfig{}
    48  	config.SetDefaults()
    49  	config.UnitPrice = 25e9
    50  	config.IstanbulCompatibleBlock = common.Big0
    51  	config.LondonCompatibleBlock = common.Big0
    52  	config.EthTxTypeCompatibleBlock = common.Big0
    53  	config.MagmaCompatibleBlock = common.Big0
    54  	config.KoreCompatibleBlock = common.Big0
    55  
    56  	sim := backends.NewSimulatedBackendWithDatabase(database.NewMemoryDBManager(), alloc, config)
    57  
    58  	// Deploy contract
    59  	owner := accounts[0]
    60  	address, tx, contract, err := govcontract.DeployGovParam(owner, sim)
    61  	require.Nil(t, err)
    62  	sim.Commit()
    63  
    64  	receipt, _ := sim.TransactionReceipt(nil, tx.Hash())
    65  	require.NotNil(t, receipt)
    66  	require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status)
    67  
    68  	return accounts, sim, address, contract
    69  }
    70  
    71  func prepareSimulatedContractWithParams(t *testing.T, params map[string][]byte) ([]*bind.TransactOpts, *backends.SimulatedBackend, common.Address, *govcontract.GovParam) {
    72  	// Create accounts and simulated blockchain
    73  	accounts, sim, address, contract := prepareSimulatedContract(t)
    74  	owner := accounts[0]
    75  
    76  	for name, val := range params {
    77  		tx, err := contract.SetParamIn(owner, name, true, val, big.NewInt(1))
    78  		require.Nil(t, err)
    79  		sim.Commit()
    80  
    81  		// check tx success
    82  		receipt, _ := sim.TransactionReceipt(nil, tx.Hash())
    83  		require.NotNil(t, receipt)
    84  		require.Equal(t, types.ReceiptStatusSuccessful, receipt.Status)
    85  	}
    86  
    87  	ab := new(big.Int).Set(sim.BlockChain().CurrentHeader().Number)
    88  	ab = ab.Add(ab, big.NewInt(1))
    89  
    90  	// check with govcontract
    91  	names, values, err := contract.GetAllParamsAt(nil, ab)
    92  	require.Nil(t, err)
    93  	require.Equal(t, len(params), len(names))
    94  	require.Equal(t, len(params), len(values))
    95  
    96  	returned := make(map[string][]byte)
    97  	for i := 0; i < len(names); i++ {
    98  		returned[names[i]] = values[i]
    99  	}
   100  
   101  	require.Equal(t, params, returned)
   102  
   103  	return accounts, sim, address, contract
   104  }
   105  
   106  func prepareContractEngine(t *testing.T, bc *blockchain.BlockChain, addr common.Address) *ContractEngine {
   107  	dbm := database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB})
   108  	dbm.WriteGovernance(map[string]interface{}{
   109  		"governance.govparamcontract": addr,
   110  	}, 0)
   111  	gov := NewGovernance(bc.Config(), dbm)
   112  	pset, err := gov.EffectiveParams(0)
   113  	require.Nil(t, err)
   114  	require.Equal(t, addr, pset.GovParamContract())
   115  
   116  	gov.SetBlockchain(bc)
   117  
   118  	e := NewContractEngine(gov)
   119  	err = e.UpdateParams(bc.CurrentBlock().NumberU64())
   120  	require.Nil(t, err)
   121  
   122  	return e
   123  }
   124  
   125  // TestContractEngine_Params tests if CurrentParams() returns the parameters required
   126  // for generating the next block. That is,
   127  //
   128  //	start          setparam       activation-1       end
   129  //
   130  // Block |---------------|---------------|---------------|
   131  //
   132  // ..............^               ^               ^
   133  // ..............t0              t1              t2
   134  //
   135  // At num = activation - 2, CurrentParams() = prev
   136  // At num = activation - 1, CurrentParams() = next
   137  //
   138  //	because next is for generating "activation" block
   139  func TestContractEngine_Params(t *testing.T) {
   140  	initialParam := map[string][]byte{
   141  		"istanbul.committeesize": {0xa},
   142  		"governance.unitprice":   {0xb},
   143  	}
   144  	accounts, sim, addr, contract := prepareSimulatedContractWithParams(t, initialParam)
   145  
   146  	e := prepareContractEngine(t, sim.BlockChain(), addr)
   147  
   148  	var (
   149  		start      = sim.BlockChain().CurrentBlock().NumberU64()
   150  		setparam   = start + 5
   151  		activation = setparam + 5
   152  		end        = activation + 5
   153  		key        = "governance.unitprice"
   154  		val        = []byte{0xff, 0xff, 0xff, 0xff}
   155  		update, _  = params.NewGovParamSetBytesMap(map[string][]byte{
   156  			key: val,
   157  		})
   158  		psetPrev, _ = params.NewGovParamSetBytesMap(initialParam)   // for t0 & t1
   159  		psetNext    = params.NewGovParamSetMerged(psetPrev, update) // for t2
   160  		owner       = accounts[0]
   161  	)
   162  
   163  	for num := start; num < end; num++ {
   164  		if num == setparam { // setParam
   165  			contract.SetParam(owner, key, true, val, new(big.Int).SetUint64(activation))
   166  		}
   167  
   168  		var expected *params.GovParamSet
   169  
   170  		if num < activation-1 { // t0 & t1
   171  			expected = psetPrev
   172  		} else { // t2
   173  			expected = psetNext
   174  		}
   175  
   176  		assert.Equal(t, expected, e.CurrentParams(), "CurrentParams() on block %d failed", num)
   177  		sim.Commit()
   178  		err := e.UpdateParams(sim.BlockChain().CurrentBlock().NumberU64())
   179  		assert.Nil(t, err)
   180  	}
   181  }
   182  
   183  // TestContractEngine_ParamsAt tests if EffectiveParams(num) returns the parameters
   184  // required for generating the "num" block. That is,
   185  //
   186  //	start          setparam       activation         end
   187  //
   188  // Block |---------------|---------------|---------------|
   189  //
   190  // ..............^               ^               ^
   191  // ..............t0              t1              t2
   192  //
   193  // EffectiveParams(activation - 1) = prev
   194  // EffectiveParams(activation)     = next
   195  func TestContractEngine_ParamsAt(t *testing.T) {
   196  	initialParam := map[string][]byte{
   197  		"istanbul.committeesize": {0xa},
   198  		"governance.unitprice":   {0xbb, 0xbb, 0xbb, 0xbb},
   199  	}
   200  	accounts, sim, addr, contract := prepareSimulatedContractWithParams(t, initialParam)
   201  
   202  	e := prepareContractEngine(t, sim.BlockChain(), addr)
   203  
   204  	var (
   205  		start      = sim.BlockChain().CurrentBlock().NumberU64()
   206  		setparam   = start + 5
   207  		activation = setparam + 5
   208  		end        = activation + 5
   209  		key        = "governance.unitprice"
   210  		val        = []byte{0xff, 0xff, 0xff, 0xff}
   211  		update, _  = params.NewGovParamSetBytesMap(map[string][]byte{
   212  			key: val,
   213  		})
   214  		psetPrev, _ = params.NewGovParamSetBytesMap(initialParam)   // for t0 & t1
   215  		psetNext    = params.NewGovParamSetMerged(psetPrev, update) // for t2
   216  		owner       = accounts[0]
   217  	)
   218  
   219  	for num := start; num < end; num++ {
   220  		if num == setparam { // setParam
   221  			contract.SetParam(owner, key, true, val, new(big.Int).SetUint64(activation))
   222  		}
   223  
   224  		for iter := start + 1; iter <= num; iter++ {
   225  			var expected *params.GovParamSet
   226  
   227  			if iter < activation { // t0 & t1
   228  				expected = psetPrev
   229  			} else { // t2
   230  				expected = psetNext
   231  			}
   232  
   233  			result, _ := e.EffectiveParams(iter)
   234  			assert.Equal(t, expected, result, "EffectiveParams(%d) on block %d failed", iter, num)
   235  		}
   236  
   237  		sim.Commit()
   238  		err := e.UpdateParams(sim.BlockChain().CurrentBlock().NumberU64())
   239  		assert.Nil(t, err)
   240  	}
   241  }