Skip to content

Commit

Permalink
Deploy burn contract by default on EIP-1559 enabled (#1648)
Browse files Browse the repository at this point in the history
  • Loading branch information
stana-miric committed Jun 26, 2023
1 parent 807ca08 commit 6c6e969
Show file tree
Hide file tree
Showing 23 changed files with 264 additions and 81 deletions.
1 change: 0 additions & 1 deletion .github/workflows/deploy.nightly.devnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ jobs:
{% for item in hostvars %}{% if (hostvars[item].tags.Role == "fullnode" or hostvars[item].tags.Role == "validator") %} --premine $(cat {{ hostvars[item].tags["Name"] }}.json | jq -r '.[0].address'):1000000000000000000000000 {% endif %}{% endfor %} \
--premine {{ loadtest_account }}:1000000000000000000000000000 \
--premine $BURN_CONTRACT_ADDRESS \
--burn-contract 0:$BURN_CONTRACT_ADDRESS \
--reward-wallet 0x0101010101010101010101010101010101010101:1000000000000000000000000000 \
--premine 0xA39Fed214820cF843E2Bcd6cA1759257a530894B:1000000000000000000000000000 \
--premine 0x181d9fEc79EC674DD3cB30dd9dd4188E737939FE:1000000000000000000000000000 \
Expand Down
8 changes: 5 additions & 3 deletions chain/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ type Params struct {
BridgeBlockList *AddressListConfig `json:"bridgeBlockList,omitempty"`

// Governance contract where the token will be sent to and burn in london fork
BurnContract map[uint64]string `json:"burnContract"`
BurnContract map[uint64]types.Address `json:"burnContract"`
// Destination address to initialize default burn contract with
BurnContractDestinationAddress types.Address `json:"burnContractDestinationAddress,omitempty"`
}

type AddressListConfig struct {
Expand Down Expand Up @@ -58,11 +60,11 @@ func (p *Params) CalculateBurnContract(block uint64) (types.Address, error) {

for i := 0; i < len(blocks)-1; i++ {
if block >= blocks[i] && block < blocks[i+1] {
return types.StringToAddress(p.BurnContract[blocks[i]]), nil
return p.BurnContract[blocks[i]], nil
}
}

return types.StringToAddress(p.BurnContract[blocks[len(blocks)-1]]), nil
return p.BurnContract[blocks[len(blocks)-1]], nil
}

func (p *Params) GetEngine() string {
Expand Down
22 changes: 11 additions & 11 deletions chain/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,43 +64,43 @@ func TestParams_CalculateBurnContract(t *testing.T) {

tests := []struct {
name string
burnContract map[uint64]string
burnContract map[uint64]types.Address
block uint64
want types.Address
wantErr bool
}{
{
name: "no addresses in the list",
burnContract: map[uint64]string{},
burnContract: map[uint64]types.Address{},
block: 10,
want: types.ZeroAddress,
wantErr: true,
},
{
name: "last address is used",
burnContract: map[uint64]string{
15: "0x8888f1f195afa192cfee860698584c030f4c9db1",
burnContract: map[uint64]types.Address{
15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"),
},
block: 10,
want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"),
wantErr: false,
},
{
name: "first address is used",
burnContract: map[uint64]string{
5: "0x8888f1f195afa192cfee860698584c030f4c9db2",
15: "0x8888f1f195afa192cfee860698584c030f4c9db1",
burnContract: map[uint64]types.Address{
5: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db2"),
15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db1"),
},
block: 10,
want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c9db2"),
wantErr: false,
},
{
name: "same block as key",
burnContract: map[uint64]string{
5: "0x8888f1f195afa192cfee860698584c030f4c4db2",
10: "0x8888f1f195afa192cfee860698584c030f4c5db1",
15: "0x8888f1f195afa192cfee860698584c030f4c6db0",
burnContract: map[uint64]types.Address{
5: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c4db2"),
10: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c5db1"),
15: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c6db0"),
},
block: 10,
want: types.StringToAddress("0x8888f1f195afa192cfee860698584c030f4c5db1"),
Expand Down
8 changes: 4 additions & 4 deletions command/genesis/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ func setFlags(cmd *cobra.Command) {
"the maximum amount of gas used by all transactions in a block",
)

cmd.Flags().StringArrayVar(
&params.burnContracts,
cmd.Flags().StringVar(
&params.burnContract,
burnContractFlag,
[]string{},
"the burn contract blocks and addresses (format: <block>:<address>)",
"",
"the burn contract block and address (format: <block>:<address>[:<burn destination>])",
)

cmd.Flags().StringArrayVar(
Expand Down
55 changes: 44 additions & 11 deletions command/genesis/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ type genesisParams struct {
blockGasLimit uint64
isPos bool

burnContracts []string
burnContract string

minNumValidators uint64
maxNumValidators uint64
Expand Down Expand Up @@ -147,6 +147,10 @@ func (p *genesisParams) validateFlags() error {
return err
}

if err := p.validateBurnContract(); err != nil {
return err
}

if err := p.validateRewardWallet(); err != nil {
return err
}
Expand Down Expand Up @@ -368,7 +372,7 @@ func (p *genesisParams) generateGenesis() error {
func (p *genesisParams) initGenesisConfig() error {
// Disable london hardfork if burn contract address is not provided
enabledForks := chain.AllForksEnabled
if len(p.burnContracts) == 0 {
if !p.isBurnContractEnabled() {
enabledForks.RemoveFork(chain.London)
}

Expand All @@ -389,19 +393,19 @@ func (p *genesisParams) initGenesisConfig() error {
Bootnodes: p.bootnodes,
}

if len(p.burnContracts) > 0 {
// burn contract can be set only for non mintable native token
if p.isBurnContractEnabled() {
chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee
chainConfig.Genesis.BaseFeeEM = command.DefaultGenesisBaseFeeEM
chainConfig.Params.BurnContract = make(map[uint64]string, len(p.burnContracts))
chainConfig.Params.BurnContract = make(map[uint64]types.Address, 1)

for _, burnContract := range p.burnContracts {
block, address, err := parseBurnContractInfo(burnContract)
if err != nil {
return err
}

chainConfig.Params.BurnContract[block] = address.String()
burnContractInfo, err := parseBurnContractInfo(p.burnContract)
if err != nil {
return err
}

chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = burnContractInfo.Address
chainConfig.Params.BurnContractDestinationAddress = burnContractInfo.DestinationAddress
}

// Predeploy staking smart contract if needed
Expand Down Expand Up @@ -472,6 +476,35 @@ func (p *genesisParams) validateRewardWallet() error {
return nil
}

// validateBurnContract validates burn contract. If native token is mintable,
// burn contract flag must not be set. If native token is non mintable only one burn contract
// can be set and the specified address will be used to predeploy default EIP1559 burn contract.
func (p *genesisParams) validateBurnContract() error {
if p.isBurnContractEnabled() {
burnContractInfo, err := parseBurnContractInfo(p.burnContract)
if err != nil {
return fmt.Errorf("invalid burn contract info provided: %w", err)
}

if p.nativeTokenConfig.IsMintable {
if burnContractInfo.Address != types.ZeroAddress {
return errors.New("only zero address is allowed as burn destination for mintable native token")
}
} else {
if burnContractInfo.Address == types.ZeroAddress {
return errors.New("it is not allowed to deploy burn contract to 0x0 address")
}
}
}

return nil
}

// isBurnContractEnabled returns true in case burn contract info is provided
func (p *genesisParams) isBurnContractEnabled() bool {
return p.burnContract != ""
}

// extractNativeTokenMetadata parses provided native token metadata (such as name, symbol and decimals count)
func (p *genesisParams) extractNativeTokenMetadata() error {
if p.nativeTokenConfigRaw == "" {
Expand Down
57 changes: 39 additions & 18 deletions command/genesis/polybft_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er

// Disable london hardfork if burn contract address is not provided
enabledForks := chain.AllForksEnabled
if len(p.burnContracts) == 0 {
if !p.isBurnContractEnabled() {
enabledForks.RemoveFork(chain.London)
}

Expand All @@ -174,8 +174,29 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
Bootnodes: p.bootnodes,
}

burnContractAddr := types.ZeroAddress

if p.isBurnContractEnabled() {
chainConfig.Params.BurnContract = make(map[uint64]types.Address, 1)

burnContractInfo, err := parseBurnContractInfo(p.burnContract)
if err != nil {
return err
}

if !p.nativeTokenConfig.IsMintable {
// burn contract can be specified on arbitrary address for non-mintable native tokens
burnContractAddr = burnContractInfo.Address
chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = burnContractAddr
chainConfig.Params.BurnContractDestinationAddress = burnContractInfo.DestinationAddress
} else {
// burnt funds are sent to zero address when dealing with mintable native tokens
chainConfig.Params.BurnContract[burnContractInfo.BlockNumber] = types.ZeroAddress
}
}

// deploy genesis contracts
allocs, err := p.deployContracts(rewardTokenByteCode, polyBftConfig)
allocs, err := p.deployContracts(rewardTokenByteCode, polyBftConfig, chainConfig, burnContractAddr)
if err != nil {
return err
}
Expand All @@ -192,19 +213,6 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
}
}

if len(p.burnContracts) > 0 {
chainConfig.Params.BurnContract = make(map[uint64]string, len(p.burnContracts))

for _, burnContract := range p.burnContracts {
block, addr, err := parseBurnContractInfo(burnContract)
if err != nil {
return err
}

chainConfig.Params.BurnContract[block] = addr.String()
}
}

validatorMetadata := make([]*validator.ValidatorMetadata, len(initialValidators))

for i, validator := range initialValidators {
Expand Down Expand Up @@ -291,7 +299,7 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
}
}

if len(p.burnContracts) > 0 {
if p.isBurnContractEnabled() {
// only populate base fee and base fee multiplier values if burn contract(s)
// is provided
chainConfig.Genesis.BaseFee = command.DefaultGenesisBaseFee
Expand All @@ -301,8 +309,11 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er
return helper.WriteGenesisConfigToDisk(chainConfig, params.genesisPath)
}

func (p *genesisParams) deployContracts(rewardTokenByteCode []byte,
polybftConfig *polybft.PolyBFTConfig) (map[types.Address]*chain.GenesisAccount, error) {
func (p *genesisParams) deployContracts(
rewardTokenByteCode []byte,
polybftConfig *polybft.PolyBFTConfig,
chainConfig *chain.Chain,
burnContractAddr types.Address) (map[types.Address]*chain.GenesisAccount, error) {
type contractInfo struct {
artifact *artifact.Artifact
address types.Address
Expand Down Expand Up @@ -360,6 +371,16 @@ func (p *genesisParams) deployContracts(rewardTokenByteCode []byte,
artifact: contractsapi.NativeERC20,
address: contracts.NativeERC20TokenContract,
})

// burn contract can be set only for non-mintable native token. If burn contract is set,
// default EIP1559 contract will be deployed.
if p.isBurnContractEnabled() {
genesisContracts = append(genesisContracts,
&contractInfo{
artifact: contractsapi.EIP1559Burn,
address: burnContractAddr,
})
}
} else {
genesisContracts = append(genesisContracts,
&contractInfo{
Expand Down
36 changes: 29 additions & 7 deletions command/genesis/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,43 @@ func parseTrackerStartBlocks(trackerStartBlocksRaw []string) (map[types.Address]
}

// parseBurnContractInfo parses provided burn contract information and returns burn contract block and address
func parseBurnContractInfo(burnContractInfoRaw string) (uint64, types.Address, error) {
// <block>:<address>
func parseBurnContractInfo(burnContractInfoRaw string) (*polybft.BurnContractInfo, error) {
// <block>:<address>[:<burn destination address>]
burnContractParts := strings.Split(burnContractInfoRaw, ":")
if len(burnContractParts) != 2 {
return 0, types.ZeroAddress, fmt.Errorf("expected format: <block>:<address>")
if len(burnContractParts) < 2 || len(burnContractParts) > 3 {
return nil, fmt.Errorf("expected format: <block>:<address>[:<burn destination>]")
}

blockRaw := burnContractParts[0]

block, err := types.ParseUint256orHex(&blockRaw)
blockNum, err := types.ParseUint64orHex(&blockRaw)
if err != nil {
return 0, types.ZeroAddress, fmt.Errorf("failed to parse amount %s: %w", blockRaw, err)
return nil, fmt.Errorf("failed to parse block number %s: %w", blockRaw, err)
}

return block.Uint64(), types.StringToAddress(burnContractParts[1]), nil
contractAddress := burnContractParts[1]
if err = types.IsValidAddress(contractAddress); err != nil {
return nil, fmt.Errorf("failed to parse contract address %s: %w", contractAddress, err)
}

if len(burnContractParts) == 2 {
return &polybft.BurnContractInfo{
BlockNumber: blockNum,
Address: types.StringToAddress(contractAddress),
DestinationAddress: types.ZeroAddress,
}, nil
}

destinationAddress := burnContractParts[2]
if err = types.IsValidAddress(destinationAddress); err != nil {
return nil, fmt.Errorf("failed to parse burn destination address %s: %w", destinationAddress, err)
}

return &polybft.BurnContractInfo{
BlockNumber: blockNum,
Address: types.StringToAddress(contractAddress),
DestinationAddress: types.StringToAddress(destinationAddress),
}, nil
}

// GetValidatorKeyFiles returns file names which has validator secrets
Expand Down
4 changes: 2 additions & 2 deletions consensus/ibft/fork/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,8 +279,8 @@ func newTestTransition(

ex := state.NewExecutor(&chain.Params{
Forks: chain.AllForksEnabled,
BurnContract: map[uint64]string{
0: types.ZeroAddress.String(),
BurnContract: map[uint64]types.Address{
0: types.ZeroAddress,
},
}, st, hclog.NewNullLogger())

Expand Down
4 changes: 4 additions & 0 deletions consensus/polybft/contractsapi/artifacts-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ func main() {
"child/validator/ValidatorSet.sol",
"ValidatorSet",
},
{
"child/EIP1559Burn.sol",
"EIP1559Burn",
},
}

for _, v := range readContracts {
Expand Down
9 changes: 9 additions & 0 deletions consensus/polybft/contractsapi/bindings-gen/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,15 @@ func main() {
},
[]string{},
},
{
"EIP1559Burn",
gensc.EIP1559Burn,
false,
[]string{
"initialize",
},
[]string{},
},
}

generatedData := &generatedData{}
Expand Down
Loading

0 comments on commit 6c6e969

Please sign in to comment.