From 4cf4b799ab0f98470e15516afcf40a10cf255a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Negovanovi=C4=87?= <93934272+Stefan-Ethernal@users.noreply.github.com> Date: Tue, 4 Jul 2023 15:18:26 +0200 Subject: [PATCH] Ensure premining reserve account (0x0 address) (#1685) * Ensure that escrow account is premined in the genesis * Rename escrow to reserve --------- Co-authored-by: Victor Castell --- command/genesis/params.go | 41 +++++++++++++++++---- command/genesis/params_test.go | 59 +++++++++++++++++++++++++++++++ command/genesis/polybft_params.go | 9 ++--- 3 files changed, 95 insertions(+), 14 deletions(-) diff --git a/command/genesis/params.go b/command/genesis/params.go index 3524a6712f..c27f99ce9d 100644 --- a/command/genesis/params.go +++ b/command/genesis/params.go @@ -61,7 +61,8 @@ var ( errInvalidEpochSize = errors.New("epoch size must be greater than 1") errInvalidTokenParams = errors.New("native token params were not submitted in proper format " + "()") - errRewardWalletAmountZero = errors.New("reward wallet amount can not be zero or negative") + errRewardWalletAmountZero = errors.New("reward wallet amount can not be zero or negative") + errReserveAccMustBePremined = errors.New("it is mandatory to premine reserve account (0x0 address)") ) type genesisParams struct { @@ -124,6 +125,8 @@ type genesisParams struct { nativeTokenConfigRaw string nativeTokenConfig *polybft.TokenConfig + premineInfos []*premineInfo + // rewards rewardTokenCode string rewardWallet string @@ -154,6 +157,10 @@ func (p *genesisParams) validateFlags() error { if err := p.validateRewardWallet(); err != nil { return err } + + if err := p.validatePremineInfo(); err != nil { + return err + } } // Check if the genesis file already exists @@ -418,12 +425,7 @@ func (p *genesisParams) initGenesisConfig() error { chainConfig.Genesis.Alloc[staking.AddrStakingContract] = stakingAccount } - for _, premineRaw := range p.premine { - premineInfo, err := parsePremineInfo(premineRaw) - if err != nil { - return err - } - + for _, premineInfo := range p.premineInfos { chainConfig.Genesis.Alloc[premineInfo.address] = &chain.GenesisAccount{ Balance: premineInfo.amount, } @@ -476,6 +478,31 @@ func (p *genesisParams) validateRewardWallet() error { return nil } +// validatePremineInfo validates whether reserve account (0x0 address) is premined +func (p *genesisParams) validatePremineInfo() error { + p.premineInfos = make([]*premineInfo, 0, len(p.premine)) + isReserveAccPremined := false + + for _, premine := range p.premine { + premineInfo, err := parsePremineInfo(premine) + if err != nil { + return fmt.Errorf("invalid premine balance amount provided: %w", err) + } + + p.premineInfos = append(p.premineInfos, premineInfo) + + if premineInfo.address == types.ZeroAddress { + isReserveAccPremined = true + } + } + + if !isReserveAccPremined { + return errReserveAccMustBePremined + } + + 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. diff --git a/command/genesis/params_test.go b/command/genesis/params_test.go index 601db39b03..5534a82002 100644 --- a/command/genesis/params_test.go +++ b/command/genesis/params_test.go @@ -1,10 +1,13 @@ package genesis import ( + "fmt" "testing" "github.com/stretchr/testify/require" + "github.com/umbracle/ethgo" + "github.com/0xPolygon/polygon-edge/command" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/types" ) @@ -116,3 +119,59 @@ func Test_extractNativeTokenMetadata(t *testing.T) { }) } } + +func Test_validatePremineInfo(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + premineRaw []string + expectedPremines []*premineInfo + expectErrMsg string + }{ + { + name: "invalid premine balance", + premineRaw: []string{"0x12345:loremIpsum"}, + expectedPremines: []*premineInfo{}, + expectErrMsg: "invalid premine balance amount provided", + }, + { + name: "missing zero address premine", + premineRaw: []string{types.StringToAddress("12").String()}, + expectedPremines: []*premineInfo{ + {address: types.StringToAddress("12"), amount: command.DefaultPremineBalance}, + }, + expectErrMsg: errReserveAccMustBePremined.Error(), + }, + { + name: "valid premine information", + premineRaw: []string{ + fmt.Sprintf("%s:%d", types.StringToAddress("1"), ethgo.Ether(10)), + fmt.Sprintf("%s:%d", types.ZeroAddress, ethgo.Ether(10000)), + }, + expectedPremines: []*premineInfo{ + {address: types.StringToAddress("1"), amount: ethgo.Ether(10)}, + {address: types.ZeroAddress, amount: ethgo.Ether(10000)}, + }, + expectErrMsg: "", + }, + } + + for _, c := range cases { + c := c + t.Run(c.name, func(t *testing.T) { + t.Parallel() + + p := &genesisParams{premine: c.premineRaw} + err := p.validatePremineInfo() + + if c.expectErrMsg != "" { + require.ErrorContains(t, err, c.expectErrMsg) + } else { + require.NoError(t, err) + } + + require.Equal(t, c.expectedPremines, p.premineInfos) + }) + } +} diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index b141788c44..02677a48cb 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -74,13 +74,8 @@ func (p *genesisParams) generatePolyBftChainConfig(o command.OutputFormatter) er // populate premine balance map premineBalances := make(map[types.Address]*premineInfo, len(p.premine)) - for _, premine := range p.premine { - premineInfo, err := parsePremineInfo(premine) - if err != nil { - return fmt.Errorf("invalid balance amount provided '%s' : %w", premine, err) - } - - premineBalances[premineInfo.address] = premineInfo + for _, premine := range p.premineInfos { + premineBalances[premine.address] = premine } walletPremineInfo, err := parsePremineInfo(p.rewardWallet)