gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/core/systemcontracts/upgrade.go (about)

     1  package systemcontracts
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"strings"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/core/state"
    12  	"github.com/ethereum/go-ethereum/log"
    13  	"github.com/ethereum/go-ethereum/params"
    14  )
    15  
    16  type UpgradeConfig struct {
    17  	BeforeUpgrade upgradeHook
    18  	AfterUpgrade  upgradeHook
    19  	ContractAddr  common.Address
    20  	CommitUrl     string
    21  	Code          string
    22  }
    23  
    24  type Upgrade struct {
    25  	UpgradeName string
    26  	Configs     []*UpgradeConfig
    27  }
    28  
    29  type upgradeHook func(blockNumber *big.Int, contractAddr common.Address, statedb *state.StateDB) error
    30  
    31  const (
    32  	mainNet    = "Mainnet"
    33  	chapelNet  = "Chapel"
    34  	rialtoNet  = "Rialto"
    35  	defaultNet = "Default"
    36  )
    37  
    38  var (
    39  	GenesisHash common.Hash
    40  )
    41  
    42  func init() {
    43  	// reserved for future use to instantiate Upgrade vars
    44  }
    45  
    46  func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, statedb *state.StateDB) error {
    47  	if config == nil || blockNumber == nil || statedb == nil {
    48  		return nil
    49  	}
    50  	var network string
    51  	switch GenesisHash {
    52  	/* Add mainnet genesis hash */
    53  	case params.BSCGenesisHash:
    54  		network = mainNet
    55  	case params.ChapelGenesisHash:
    56  		network = chapelNet
    57  	case params.RialtoGenesisHash:
    58  		network = rialtoNet
    59  	default:
    60  		network = defaultNet
    61  	}
    62  
    63  	logger := log.New("system-contract-upgrade", network)
    64  
    65  	if config.IsPrimordialPulseBlock(blockNumber.Uint64()) {
    66  		configs, err := primordialPulseUpgrade(config)
    67  		if err != nil {
    68  			return err
    69  		}
    70  		applySystemContractUpgrade(&Upgrade{
    71  			UpgradeName: "PrimordialPulse",
    72  			Configs:     configs,
    73  		}, blockNumber, statedb, logger)
    74  
    75  		// reset system contract balances to 0, in case of carry-over funds from ETH state
    76  		for _, cfg := range configs {
    77  			logger.Info(fmt.Sprintf("Resetting contract %s balance to 0", cfg.ContractAddr.String()))
    78  			statedb.SetBalance(cfg.ContractAddr, big.NewInt(0))
    79  		}
    80  	} else {
    81  		logger.Debug("No system contract updates to apply", "height", blockNumber.String())
    82  	}
    83  
    84  	return nil
    85  }
    86  
    87  func primordialPulseUpgrade(config *params.ChainConfig) ([]*UpgradeConfig, error) {
    88  	if config.Parlia.SystemContracts == nil {
    89  		return nil, errors.New("Missing systemContracts in parlia config for PrimordialPulse fork")
    90  	}
    91  
    92  	upgrades := make([]*UpgradeConfig, len(*config.Parlia.SystemContracts))
    93  	for i, contract := range *config.Parlia.SystemContracts {
    94  		upgrades[i] = &UpgradeConfig{
    95  			ContractAddr: common.HexToAddress(contract.Addr),
    96  			Code:         contract.Code,
    97  		}
    98  	}
    99  
   100  	return upgrades, nil
   101  }
   102  
   103  func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb *state.StateDB, logger log.Logger) {
   104  	if upgrade == nil {
   105  		logger.Info("Empty upgrade config", "height", blockNumber.String())
   106  		return
   107  	}
   108  
   109  	logger.Info(fmt.Sprintf("Applying upgrade %s at height %d", upgrade.UpgradeName, blockNumber.Int64()))
   110  	for _, cfg := range upgrade.Configs {
   111  		logger.Info(fmt.Sprintf("Upgrade contract %s to commit %s", cfg.ContractAddr.String(), cfg.CommitUrl))
   112  
   113  		if cfg.BeforeUpgrade != nil {
   114  			err := cfg.BeforeUpgrade(blockNumber, cfg.ContractAddr, statedb)
   115  			if err != nil {
   116  				panic(fmt.Errorf("contract address: %s, execute beforeUpgrade error: %s", cfg.ContractAddr.String(), err.Error()))
   117  			}
   118  		}
   119  
   120  		newContractCode, err := hex.DecodeString(strings.TrimPrefix(cfg.Code, "0x"))
   121  		if err != nil {
   122  			panic(fmt.Errorf("failed to decode new contract code: %s", err.Error()))
   123  		}
   124  		statedb.SetCode(cfg.ContractAddr, newContractCode)
   125  
   126  		if cfg.AfterUpgrade != nil {
   127  			err := cfg.AfterUpgrade(blockNumber, cfg.ContractAddr, statedb)
   128  			if err != nil {
   129  				panic(fmt.Errorf("contract address: %s, execute afterUpgrade error: %s", cfg.ContractAddr.String(), err.Error()))
   130  			}
   131  		}
   132  	}
   133  }