From d239096308ae750e13aa76440de3a797383e60e7 Mon Sep 17 00:00:00 2001 From: Victor Castell Date: Thu, 1 Dec 2022 11:27:53 +0100 Subject: [PATCH] Removing `GenesisTarget` and adding the `NodeID` field to `Validator` struct (#985) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactored GenesisTarget removing it and adding the NodeID field to Validator struct. * Refactored generatePolyBFTConfig to use the new struct and simplify the code and take into account validators passed from params * Add NodeID as a field needed for validators passed from params * Tune timeout for bridge test Co-authored-by: Stefan Negovanović --- command/genesis/polybft_params.go | 181 ++++++++---------- command/genesis/utils.go | 21 +- .../rootchain/initcontracts/init_contracts.go | 15 +- consensus/polybft/polybft_config.go | 13 ++ e2e-polybft/bridge_test.go | 2 +- e2e-polybft/framework/test-cluster.go | 2 +- 6 files changed, 120 insertions(+), 114 deletions(-) diff --git a/command/genesis/polybft_params.go b/command/genesis/polybft_params.go index 0a9c2924fe..60db53b664 100644 --- a/command/genesis/polybft_params.go +++ b/command/genesis/polybft_params.go @@ -2,7 +2,6 @@ package genesis import ( "bytes" - "encoding/hex" "fmt" "math/big" "path" @@ -17,7 +16,6 @@ import ( rootchain "github.com/0xPolygon/polygon-edge/command/rootchain/helper" "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/bitmap" - bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/contracts" "github.com/0xPolygon/polygon-edge/server" "github.com/0xPolygon/polygon-edge/types" @@ -45,18 +43,64 @@ const ( ) func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { - validatorsInfo, err := ReadValidatorsByRegexp(path.Dir(p.genesisPath), p.polyBftValidatorPrefixPath) + // set initial validator set + genesisValidators, err := p.getGenesisValidators() if err != nil { return nil, err } + // deploy genesis contracts allocs, err := p.deployContracts() if err != nil { return nil, err } - // use 1st account as governance address - governanceAccount := validatorsInfo[0].Account + // premine accounts with some tokens + var ( + validatorPreminesMap map[types.Address]int + premineInfos []*premineInfo + ) + + if p.premineValidators != "" { + validatorPreminesMap = make(map[types.Address]int, len(genesisValidators)) + + for i, vi := range genesisValidators { + premineInfo, err := parsePremineInfo(fmt.Sprintf("%s:%s", vi.Address, p.premineValidators)) + if err != nil { + return nil, err + } + + premineInfos = append(premineInfos, premineInfo) + validatorPreminesMap[premineInfo.address] = i + } + } + + for _, premine := range p.premine { + premineInfo, err := parsePremineInfo(premine) + if err != nil { + return nil, err + } + + if i, ok := validatorPreminesMap[premineInfo.address]; ok { + premineInfos[i] = premineInfo + } else { + premineInfos = append(premineInfos, premineInfo) + } + } + + // premine accounts + fillPremineMap(allocs, premineInfos) + + // populate genesis validators balances + for _, validator := range genesisValidators { + balance, err := chain.GetGenesisAccountBalance(validator.Address, allocs) + if err != nil { + return nil, err + } + + validator.Balance = balance + } + polyBftConfig := &polybft.PolyBFTConfig{ BlockTime: p.blockTime, EpochSize: p.epochSize, @@ -64,9 +108,11 @@ func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { ValidatorSetSize: p.validatorSetSize, ValidatorSetAddr: contracts.ValidatorSetContract, StateReceiverAddr: contracts.StateReceiverContract, - Governance: types.Address(governanceAccount.Ecdsa.Address()), + // use 1st account as governance address + Governance: genesisValidators[0].Address, } + // populate bridge configuration if p.bridgeEnabled { ip, err := rootchain.ReadRootchainIP() if err != nil { @@ -94,64 +140,15 @@ func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { // set generic validators as bootnodes if needed if len(p.bootnodes) == 0 { - for i, validator := range validatorsInfo { - bnode := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", "127.0.0.1", bootnodePortStart+i, validator.NodeID) - chainConfig.Bootnodes = append(chainConfig.Bootnodes, bnode) + for i, validator := range genesisValidators { + bootNode := fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s", "127.0.0.1", bootnodePortStart+i, validator.NodeID) + chainConfig.Bootnodes = append(chainConfig.Bootnodes, bootNode) } } - var ( - validatorPreminesMap map[types.Address]int - premineInfos []*premineInfo - ) - - if p.premineValidators != "" { - validatorPreminesMap = make(map[types.Address]int, len(validatorsInfo)) - - for i, vi := range validatorsInfo { - premineInfo, err := parsePremineInfo(fmt.Sprintf("%s:%s", - vi.Account.Ecdsa.Address().String(), p.premineValidators)) - if err != nil { - return nil, err - } - - premineInfos = append(premineInfos, premineInfo) - validatorPreminesMap[premineInfo.address] = i - } - } - - if len(p.premine) > 0 { - for _, premine := range p.premine { - premineInfo, err := parsePremineInfo(premine) - if err != nil { - return nil, err - } - - if i, ok := validatorPreminesMap[premineInfo.address]; ok { - premineInfos[i] = premineInfo - } else { - premineInfos = append(premineInfos, premineInfo) - } - } - } - - // premine accounts - fillPremineMap(allocs, premineInfos) - - // set initial validator set - genesisValidators, err := p.getGenesisValidators(validatorsInfo, allocs) - if err != nil { - return nil, err - } - polyBftConfig.InitialValidatorSet = genesisValidators - pubKeys := make([]*bls.PublicKey, len(validatorsInfo)) - for i, validatorInfo := range validatorsInfo { - pubKeys[i] = validatorInfo.Account.Bls.PublicKey() - } - - genesisExtraData, err := generateExtraDataPolyBft(genesisValidators, pubKeys) + genesisExtraData, err := generateExtraDataPolyBft(genesisValidators) if err != nil { return nil, err } @@ -169,49 +166,40 @@ func (p *genesisParams) generatePolyBFTConfig() (*chain.Chain, error) { return chainConfig, nil } -func (p *genesisParams) getGenesisValidators(validators []GenesisTarget, - allocs map[types.Address]*chain.GenesisAccount) ([]*polybft.Validator, error) { - result := make([]*polybft.Validator, 0) - +func (p *genesisParams) getGenesisValidators() ([]*polybft.Validator, error) { if len(p.validators) > 0 { - for _, validator := range p.validators { + validators := make([]*polybft.Validator, len(p.validators)) + for i, validator := range p.validators { parts := strings.Split(validator, ":") - if len(parts) != 2 || len(parts[0]) != 32 || len(parts[1]) < 2 { - continue - } - addr := types.StringToAddress(parts[0]) + if len(parts) != 3 { + return nil, fmt.Errorf("expected 3 parts provided in the following format , but got %d", + len(parts)) + } - balance, err := chain.GetGenesisAccountBalance(addr, allocs) - if err != nil { - return nil, err + if len(parts[0]) != 53 { + return nil, fmt.Errorf("invalid node id: %s", parts[0]) } - result = append(result, &polybft.Validator{ - Address: addr, - BlsKey: parts[1], - Balance: balance, - }) - } - } else { - for _, validator := range validators { - pubKeyMarshalled := validator.Account.Bls.PublicKey().Marshal() - addr := types.Address(validator.Account.Ecdsa.Address()) + if len(parts[1]) != 42 { + return nil, fmt.Errorf("invalid address: %s", parts[1]) + } - balance, err := chain.GetGenesisAccountBalance(addr, allocs) - if err != nil { - return nil, err + if len(parts[2]) < 2 { + return nil, fmt.Errorf("invalid bls key: %s", parts[2]) } - result = append(result, &polybft.Validator{ - Address: addr, - BlsKey: hex.EncodeToString(pubKeyMarshalled), - Balance: balance, - }) + validators[i] = &polybft.Validator{ + NodeID: parts[0], + Address: types.StringToAddress(parts[1]), + BlsKey: parts[2], + } } + + return validators, nil } - return result, nil + return ReadValidatorsByRegexp(path.Dir(p.genesisPath), p.polyBftValidatorPrefixPath) } func (p *genesisParams) generatePolyBftGenesis() error { @@ -279,20 +267,21 @@ func (p *genesisParams) deployContracts() (map[types.Address]*chain.GenesisAccou } // generateExtraDataPolyBft populates Extra with specific fields required for polybft consensus protocol -func generateExtraDataPolyBft(validators []*polybft.Validator, publicKeys []*bls.PublicKey) ([]byte, error) { - if len(validators) != len(publicKeys) { - return nil, fmt.Errorf("expected same length for genesis validators and BLS public keys") - } - +func generateExtraDataPolyBft(validators []*polybft.Validator) ([]byte, error) { delta := &polybft.ValidatorSetDelta{ Added: make(polybft.AccountSet, len(validators)), Removed: bitmap.Bitmap{}, } for i, validator := range validators { + blsKey, err := validator.UnmarshalBLSPublicKey() + if err != nil { + return nil, err + } + delta.Added[i] = &polybft.ValidatorMetadata{ Address: validator.Address, - BlsKey: publicKeys[i], + BlsKey: blsKey, VotingPower: chain.ConvertWeiToTokensAmount(validator.Balance).Uint64(), } } diff --git a/command/genesis/utils.go b/command/genesis/utils.go index eb6bd700b3..be63f2726d 100644 --- a/command/genesis/utils.go +++ b/command/genesis/utils.go @@ -1,6 +1,7 @@ package genesis import ( + "encoding/hex" "fmt" "io/ioutil" "math/big" @@ -12,6 +13,7 @@ import ( "github.com/0xPolygon/polygon-edge/chain" "github.com/0xPolygon/polygon-edge/command" + "github.com/0xPolygon/polygon-edge/consensus/polybft" "github.com/0xPolygon/polygon-edge/consensus/polybft/wallet" "github.com/0xPolygon/polygon-edge/secrets" "github.com/0xPolygon/polygon-edge/secrets/helper" @@ -96,12 +98,7 @@ func parsePremineInfo(premineInfoRaw string) (*premineInfo, error) { return &premineInfo{address: address, balance: amount}, nil } -type GenesisTarget struct { - Account *wallet.Account - NodeID string -} - -func ReadValidatorsByRegexp(dir, prefix string) ([]GenesisTarget, error) { +func ReadValidatorsByRegexp(dir, prefix string) ([]*polybft.Validator, error) { if dir == "" { dir = "." } @@ -132,9 +129,9 @@ func ReadValidatorsByRegexp(dir, prefix string) ([]GenesisTarget, error) { return num1 < num2 }) - validators := make([]GenesisTarget, 0, len(files)) + validators := make([]*polybft.Validator, len(files)) - for _, file := range files { + for i, file := range files { path := filepath.Join(dir, file.Name()) account, nodeID, err := getSecrets(path) @@ -142,8 +139,12 @@ func ReadValidatorsByRegexp(dir, prefix string) ([]GenesisTarget, error) { return nil, err } - target := GenesisTarget{Account: account, NodeID: nodeID} - validators = append(validators, target) + validator := &polybft.Validator{ + Address: types.Address(account.Ecdsa.Address()), + BlsKey: hex.EncodeToString(account.Bls.PublicKey().Marshal()), + NodeID: nodeID, + } + validators[i] = validator } return validators, nil diff --git a/command/rootchain/initcontracts/init_contracts.go b/command/rootchain/initcontracts/init_contracts.go index dc2d6cd888..021aed7be5 100644 --- a/command/rootchain/initcontracts/init_contracts.go +++ b/command/rootchain/initcontracts/init_contracts.go @@ -264,21 +264,24 @@ func validatorSetToABISlice(allocs map[types.Address]*chain.GenesisAccount) ([]m validatorSetMap := make([]map[string]interface{}, len(validatorsInfo)) sort.Slice(validatorsInfo, func(i, j int) bool { - return bytes.Compare(validatorsInfo[i].Account.Ecdsa.Address().Bytes(), - validatorsInfo[j].Account.Ecdsa.Address().Bytes()) < 0 + return bytes.Compare(validatorsInfo[i].Address.Bytes(), + validatorsInfo[j].Address.Bytes()) < 0 }) for i, validatorInfo := range validatorsInfo { - addr := types.Address(validatorInfo.Account.Ecdsa.Address()) + genesisBalance, err := chain.GetGenesisAccountBalance(validatorInfo.Address, allocs) + if err != nil { + return nil, err + } - genesisBalance, err := chain.GetGenesisAccountBalance(addr, allocs) + blsKey, err := validatorInfo.UnmarshalBLSPublicKey() if err != nil { return nil, err } validatorSetMap[i] = map[string]interface{}{ - "_address": addr, - "blsKey": validatorInfo.Account.Bls.PublicKey().ToBigInt(), + "_address": validatorInfo.Address, + "blsKey": blsKey.ToBigInt(), "votingPower": chain.ConvertWeiToTokensAmount(genesisBalance), } } diff --git a/consensus/polybft/polybft_config.go b/consensus/polybft/polybft_config.go index f09ab26c86..e767da39d9 100644 --- a/consensus/polybft/polybft_config.go +++ b/consensus/polybft/polybft_config.go @@ -1,10 +1,12 @@ package polybft import ( + "encoding/hex" "encoding/json" "math/big" "time" + bls "github.com/0xPolygon/polygon-edge/consensus/polybft/signer" "github.com/0xPolygon/polygon-edge/types" ) @@ -44,6 +46,7 @@ type Validator struct { Address types.Address `json:"address"` BlsKey string `json:"blsKey"` Balance *big.Int `json:"balance"` + NodeID string `json:"-"` } type validatorRaw struct { @@ -79,6 +82,16 @@ func (v *Validator) UnmarshalJSON(data []byte) error { return nil } +// UnmarshalBLSPublicKey unmarshals the hex encoded BLS public key +func (v *Validator) UnmarshalBLSPublicKey() (*bls.PublicKey, error) { + decoded, err := hex.DecodeString(v.BlsKey) + if err != nil { + return nil, err + } + + return bls.UnmarshalPublicKey(decoded) +} + // DebugConfig is a struct used for test configuration in init genesis type DebugConfig struct { ValidatorSetSize uint64 `json:"validatorSetSize"` diff --git a/e2e-polybft/bridge_test.go b/e2e-polybft/bridge_test.go index 0612088c9d..389a326afc 100644 --- a/e2e-polybft/bridge_test.go +++ b/e2e-polybft/bridge_test.go @@ -155,7 +155,7 @@ func TestE2E_Bridge_MainWorkflow(t *testing.T) { ) // wait for a few more sprints - require.NoError(t, cluster.WaitForBlock(25, 1*time.Minute)) + require.NoError(t, cluster.WaitForBlock(30, 2*time.Minute)) // commitments should've been stored // execute the state sysncs diff --git a/e2e-polybft/framework/test-cluster.go b/e2e-polybft/framework/test-cluster.go index 1c58a34db6..c4b259b828 100644 --- a/e2e-polybft/framework/test-cluster.go +++ b/e2e-polybft/framework/test-cluster.go @@ -258,7 +258,7 @@ func NewTestCluster(t *testing.T, validatorsCount int, opts ...ClusterOption) *T // premine all the validators by default for _, validator := range validators { - args = append(args, "--premine", validator.Account.Ecdsa.Address().String()) + args = append(args, "--premine", validator.Address.String()) } if cluster.Config.BootnodeCount > 0 {