Skip to content

Commit

Permalink
Removing GenesisTarget and adding the NodeID field to Validator
Browse files Browse the repository at this point in the history
… struct (#985)

* 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ć <[email protected]>
  • Loading branch information
vcastellm and Stefan-Ethernal authored Dec 1, 2022
1 parent 4828279 commit d239096
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 114 deletions.
181 changes: 85 additions & 96 deletions command/genesis/polybft_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package genesis

import (
"bytes"
"encoding/hex"
"fmt"
"math/big"
"path"
Expand All @@ -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"
Expand Down Expand Up @@ -45,28 +43,76 @@ 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,
SprintSize: p.sprintSize,
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 {
Expand Down Expand Up @@ -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
}
Expand All @@ -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 <nodeId:address:blsKey>, 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 {
Expand Down Expand Up @@ -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(),
}
}
Expand Down
21 changes: 11 additions & 10 deletions command/genesis/utils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package genesis

import (
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
Expand All @@ -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"
Expand Down Expand Up @@ -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 = "."
}
Expand Down Expand Up @@ -132,18 +129,22 @@ 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)
if err != nil {
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
Expand Down
15 changes: 9 additions & 6 deletions command/rootchain/initcontracts/init_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
Expand Down
13 changes: 13 additions & 0 deletions consensus/polybft/polybft_config.go
Original file line number Diff line number Diff line change
@@ -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"
)

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"`
Expand Down
Loading

0 comments on commit d239096

Please sign in to comment.