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 }