The core protocol of WoopChain
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
woop/internal/configs/sharding/instance.go

267 lines
8.0 KiB

package shardingconfig
import (
"math/big"
ethCommon "github.com/ethereum/go-ethereum/common"
"github.com/woop-chain/woop/crypto/bls"
"github.com/woop-chain/woop/internal/genesis"
"github.com/woop-chain/woop/numeric"
"github.com/pkg/errors"
)
// NetworkID is the network type of the blockchain.
type NetworkID byte
// Constants for NetworkID.
const (
MainNet NetworkID = iota
TestNet
LocalNet
Pangaea
Partner
StressNet
DevNet
)
type instance struct {
numShards uint32
numNodesPerShard int
numWoopOperatedNodesPerShard int
woopVotePercent numeric.Dec
externalVotePercent numeric.Dec
wikiAccounts []genesis.DeployAccount
fnAccounts []genesis.DeployAccount
reshardingEpoch []*big.Int
blocksPerEpoch uint64
slotsLimit int // HIP-16: The absolute number of maximum effective slots per shard limit for each validator. 0 means no limit.
allowlist Allowlist
feeCollectors FeeCollectors
emissionFraction numeric.Dec
recoveryAddress ethCommon.Address
}
type FeeCollectors map[ethCommon.Address]numeric.Dec
// NewInstance creates and validates a new sharding configuration based
// upon given parameters.
func NewInstance(
numShards uint32,
numNodesPerShard,
numWoopOperatedNodesPerShard,
slotsLimit int,
woopVotePercent numeric.Dec,
wikiAccounts []genesis.DeployAccount,
fnAccounts []genesis.DeployAccount,
allowlist Allowlist,
feeCollectors FeeCollectors,
emissionFractionToRecovery numeric.Dec,
recoveryAddress ethCommon.Address,
reshardingEpoch []*big.Int, blocksE uint64,
) (Instance, error) {
if numShards < 1 {
return nil, errors.Errorf(
"sharding config must have at least one shard have %d", numShards,
)
}
if numNodesPerShard < 1 {
return nil, errors.Errorf(
"each shard must have at least one node %d", numNodesPerShard,
)
}
if numWoopOperatedNodesPerShard < 0 {
return nil, errors.Errorf(
"Woop-operated nodes cannot be negative %d", numWoopOperatedNodesPerShard,
)
}
if numWoopOperatedNodesPerShard > numNodesPerShard {
return nil, errors.Errorf(""+
"number of Woop-operated nodes cannot exceed "+
"overall number of nodes per shard %d %d",
numWoopOperatedNodesPerShard,
numNodesPerShard,
)
}
if slotsLimit < 0 {
return nil, errors.Errorf("SlotsLimit cannot be negative %d", slotsLimit)
}
if woopVotePercent.LT(numeric.ZeroDec()) ||
woopVotePercent.GT(numeric.OneDec()) {
return nil, errors.Errorf("" +
"total voting power of woop nodes should be within [0, 1]",
)
}
if len(feeCollectors) > 0 {
total := numeric.ZeroDec() // is a copy
for _, v := range feeCollectors {
total = total.Add(v)
}
if !total.Equal(numeric.OneDec()) {
return nil, errors.Errorf(
"total fee collection percentage should be 1, but got %v", total,
)
}
}
if emissionFractionToRecovery.LT(numeric.ZeroDec()) ||
emissionFractionToRecovery.GT(numeric.OneDec()) {
return nil, errors.Errorf(
"emission split must be within [0, 1]",
)
}
if !emissionFractionToRecovery.Equal(numeric.ZeroDec()) {
if recoveryAddress == (ethCommon.Address{}) {
return nil, errors.Errorf(
"have non-zero emission split but no target address",
)
}
}
if recoveryAddress != (ethCommon.Address{}) {
if emissionFractionToRecovery.Equal(numeric.ZeroDec()) {
return nil, errors.Errorf(
"have target address but no emission split",
)
}
}
return instance{
numShards: numShards,
numNodesPerShard: numNodesPerShard,
numWoopOperatedNodesPerShard: numWoopOperatedNodesPerShard,
woopVotePercent: woopVotePercent,
externalVotePercent: numeric.OneDec().Sub(woopVotePercent),
wikiAccounts: wikiAccounts,
fnAccounts: fnAccounts,
allowlist: allowlist,
reshardingEpoch: reshardingEpoch,
blocksPerEpoch: blocksE,
slotsLimit: slotsLimit,
feeCollectors: feeCollectors,
recoveryAddress: recoveryAddress,
emissionFraction: emissionFractionToRecovery,
}, nil
}
// MustNewInstance creates a new sharding configuration based upon
// given parameters. It panics if parameter validation fails.
// It is intended to be used for static initialization.
func MustNewInstance(
numShards uint32,
numNodesPerShard, numWoopOperatedNodesPerShard int, slotsLimitPercent float32,
woopVotePercent numeric.Dec,
wikiAccounts []genesis.DeployAccount,
fnAccounts []genesis.DeployAccount,
allowlist Allowlist,
feeCollectors FeeCollectors,
emissionFractionToRecovery numeric.Dec,
recoveryAddress ethCommon.Address,
reshardingEpoch []*big.Int, blocksPerEpoch uint64,
) Instance {
slotsLimit := int(float32(numNodesPerShard-numWoopOperatedNodesPerShard) * slotsLimitPercent)
sc, err := NewInstance(
numShards, numNodesPerShard, numWoopOperatedNodesPerShard,
slotsLimit, woopVotePercent, wikiAccounts, fnAccounts,
allowlist, feeCollectors, emissionFractionToRecovery,
recoveryAddress, reshardingEpoch, blocksPerEpoch,
)
if err != nil {
panic(err)
}
return sc
}
// BlocksPerEpoch ..
func (sc instance) BlocksPerEpoch() uint64 {
return sc.blocksPerEpoch
}
// NumShards returns the number of shards in the network.
func (sc instance) NumShards() uint32 {
return sc.numShards
}
// SlotsLimit returns the max slots per shard limit for each validator
func (sc instance) SlotsLimit() int {
return sc.slotsLimit
}
// FeeCollector returns a mapping of address to decimal % of fee
func (sc instance) FeeCollectors() FeeCollectors {
return sc.feeCollectors
}
// WoopVotePercent returns total percentage of voting power woop nodes possess.
func (sc instance) WoopVotePercent() numeric.Dec {
return sc.woopVotePercent
}
// ExternalVotePercent returns total percentage of voting power external validators possess.
func (sc instance) ExternalVotePercent() numeric.Dec {
return sc.externalVotePercent
}
// NumNodesPerShard returns number of nodes in each shard.
func (sc instance) NumNodesPerShard() int {
return sc.numNodesPerShard
}
// NumWoopOperatedNodesPerShard returns number of nodes in each shard
// that are operated by Woop.
func (sc instance) NumWoopOperatedNodesPerShard() int {
return sc.numWoopOperatedNodesPerShard
}
// WikiAccounts returns the list of Woop accounts
func (sc instance) WikiAccounts() []genesis.DeployAccount {
return sc.wikiAccounts
}
// FnAccounts returns the list of Foundational Node accounts
func (sc instance) FnAccounts() []genesis.DeployAccount {
return sc.fnAccounts
}
// FindAccount returns the deploy account based on the blskey, and if the account is a leader
// or not in the bootstrapping process.
func (sc instance) FindAccount(blsPubKey string) (bool, *genesis.DeployAccount) {
for i, item := range sc.wikiAccounts {
if item.BLSPublicKey == blsPubKey {
item.ShardID = uint32(i) % sc.numShards
return uint32(i) < sc.numShards, &item
}
}
for i, item := range sc.fnAccounts {
if item.BLSPublicKey == blsPubKey {
item.ShardID = uint32(i) % sc.numShards
return false, &item
}
}
return false, nil
}
// ReshardingEpoch returns the list of epoch number
func (sc instance) ReshardingEpoch() []*big.Int {
return sc.reshardingEpoch
}
// ReshardingEpoch returns the list of epoch number
func (sc instance) GetNetworkID() NetworkID {
return DevNet
}
// ExternalAllowlist returns the list of external leader keys in allowlist(HIP18)
func (sc instance) ExternalAllowlist() []bls.PublicKeyWrapper {
return sc.allowlist.BLSPublicKeys
}
// ExternalAllowlistLimit returns the maximum number of external leader keys on each shard
func (sc instance) ExternalAllowlistLimit() int {
return sc.allowlist.MaxLimitPerShard
}
func (sc instance) HIP30RecoveryAddress() ethCommon.Address {
return sc.recoveryAddress
}
func (sc instance) HIP30EmissionFraction() numeric.Dec {
return sc.emissionFraction
}