github.com/klaytn/klaytn@v1.12.1/governance/contract.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  	"errors"
    21  	"math/big"
    22  
    23  	"github.com/klaytn/klaytn/accounts/abi/bind/backends"
    24  	"github.com/klaytn/klaytn/common"
    25  	govcontract "github.com/klaytn/klaytn/contracts/gov"
    26  	"github.com/klaytn/klaytn/params"
    27  )
    28  
    29  var (
    30  	errContractEngineNotReady = errors.New("ContractEngine is not ready")
    31  	errParamsAtFail           = errors.New("headerGov EffectiveParams() failed")
    32  	errGovParamNotExist       = errors.New("GovParam does not exist")
    33  	errInvalidGovParam        = errors.New("GovParam conversion failed")
    34  )
    35  
    36  type ContractEngine struct {
    37  	currentParams *params.GovParamSet
    38  
    39  	// for headerGov.EffectiveParams() and BlockChain()
    40  	headerGov *Governance
    41  }
    42  
    43  func NewContractEngine(headerGov *Governance) *ContractEngine {
    44  	e := &ContractEngine{
    45  		currentParams: params.NewGovParamSet(),
    46  		headerGov:     headerGov,
    47  	}
    48  
    49  	return e
    50  }
    51  
    52  // CurrentParams effective at upcoming block (head+1)
    53  func (e *ContractEngine) CurrentParams() *params.GovParamSet {
    54  	return e.currentParams
    55  }
    56  
    57  // Parameters effective at requested block (num)
    58  func (e *ContractEngine) EffectiveParams(num uint64) (*params.GovParamSet, error) {
    59  	pset, err := e.contractGetAllParamsAt(num)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	return pset, nil
    64  }
    65  
    66  // if UpdateParam fails, leave currentParams as-is
    67  func (e *ContractEngine) UpdateParams(num uint64) error {
    68  	// request the parameters required for generating the next block
    69  	pset, err := e.contractGetAllParamsAt(num + 1)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	e.currentParams = pset
    75  	return nil
    76  }
    77  
    78  // contractGetAllParamsAt sets evmCtx.BlockNumber as num
    79  func (e *ContractEngine) contractGetAllParamsAt(num uint64) (*params.GovParamSet, error) {
    80  	chain := e.headerGov.BlockChain()
    81  	if chain == nil {
    82  		logger.Crit("headerGov.BlockChain() is nil")
    83  		return nil, errContractEngineNotReady
    84  	}
    85  
    86  	config := chain.Config()
    87  	if !config.IsKoreForkEnabled(new(big.Int).SetUint64(num)) {
    88  		logger.Trace("ContractEngine disabled: hardfork block not passed")
    89  		return params.NewGovParamSet(), nil
    90  	}
    91  
    92  	addr, err := e.contractAddrAt(num)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	if common.EmptyAddress(addr) {
    97  		logger.Trace("ContractEngine disabled: GovParamContract address not set")
    98  		return params.NewGovParamSet(), nil
    99  	}
   100  
   101  	caller := backends.NewBlockchainContractBackend(chain, nil, nil)
   102  	contract, _ := govcontract.NewGovParamCaller(addr, caller)
   103  
   104  	names, values, err := contract.GetAllParamsAt(nil, new(big.Int).SetUint64(num))
   105  	if err != nil {
   106  		logger.Warn("ContractEngine disabled: getAllParams call failed", "err", err)
   107  		return params.NewGovParamSet(), nil
   108  	}
   109  
   110  	if len(names) != len(values) {
   111  		logger.Warn("ContractEngine disabled: getAllParams result invalid", "len(names)", len(names), "len(values)", len(values))
   112  		return params.NewGovParamSet(), nil
   113  	}
   114  
   115  	bytesMap := make(map[string][]byte)
   116  	for i := 0; i < len(names); i++ {
   117  		bytesMap[names[i]] = values[i]
   118  	}
   119  	return params.NewGovParamSetBytesMapTolerant(bytesMap), nil
   120  }
   121  
   122  // contractAddrAt returns the GovParamContract address effective at given block number
   123  func (e *ContractEngine) contractAddrAt(num uint64) (common.Address, error) {
   124  	headerParams, err := e.headerGov.EffectiveParams(num)
   125  	if err != nil {
   126  		logger.Error("headerGov.EffectiveParams failed", "err", err, "num", num)
   127  		return common.Address{}, errParamsAtFail
   128  	}
   129  
   130  	// this happens when GovParamContract has not been voted
   131  	param, ok := headerParams.Get(params.GovParamContract)
   132  	if !ok {
   133  		logger.Debug("Could not find GovParam contract address")
   134  		return common.Address{}, nil
   135  	}
   136  
   137  	addr, ok := param.(common.Address)
   138  	if !ok {
   139  		logger.Error("Could not convert GovParam contract address into common.Address", "param", param)
   140  		return common.Address{}, errInvalidGovParam
   141  	}
   142  
   143  	return addr, nil
   144  }