Rotate external validators for non-beacon shards. (#4373)

* Rotate only non beacon shards.

* Rotate all shards, but only hmy validators for beacon.

* Fix type.

* Revert "Fix type."

This reverts commit 0a8b506c763d9f8609abff7395ba32b18e43b149.

* Revert "Rotate all shards, but only hmy validators for beacon."

This reverts commit 70b09e2de81aa2cbffae3ccdfd4e334e7d938759.

* Fixed failed test.

* Revert "Revert "Rotate all shards, but only hmy validators for beacon.""

This reverts commit 66cfaa9817488be60ed5b5cfee1fe833ede237c8.

* Frequency by slots count.

* Fix config.

* First validator produce rest blocks.

* Updated.

* Add lock.
pull/4406/head
Konstantin 2 years ago committed by GitHub
parent 3ea6ebfa7d
commit 7d47d9e8a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      consensus/consensus.go
  2. 2
      consensus/consensus_service.go
  3. 85
      consensus/consensus_v2.go
  4. 3
      consensus/validator.go
  5. 8
      consensus/view_change.go
  6. 2
      core/blockchain.go
  7. 56
      core/blockchain_impl.go
  8. 4
      core/blockchain_stub.go
  9. 34
      core/rawdb/accessors_metadata.go
  10. 32
      core/rawdb/accessors_metadata_test.go
  11. 5
      core/rawdb/schema.go
  12. 3
      internal/configs/sharding/shardingconfig.go
  13. 468
      internal/params/config.go
  14. 6
      numeric/decimal.go
  15. 24
      numeric/decimal_test.go

@ -218,6 +218,8 @@ func (consensus *Consensus) getConsensusLeaderPrivateKey() (*bls.PrivateKeyWrapp
// SetBlockVerifier sets the block verifier
func (consensus *Consensus) SetBlockVerifier(verifier VerifyBlockFunc) {
consensus.mutex.Lock()
defer consensus.mutex.Unlock()
consensus.BlockVerifier = verifier
consensus.vc.SetVerifyBlock(consensus.verifyBlock)
}

@ -547,7 +547,7 @@ func (consensus *Consensus) GetFinality() int64 {
return consensus.finality
}
// switchPhase will switch FBFTPhase to nextPhase if the desirePhase equals the nextPhase
// switchPhase will switch FBFTPhase to desired phase.
func (consensus *Consensus) switchPhase(subject string, desired FBFTPhase) {
consensus.getLogger().Info().
Str("from:", consensus.phase.String()).

@ -13,7 +13,6 @@ import (
"github.com/harmony-one/harmony/consensus/signature"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/rs/zerolog"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
@ -688,40 +687,70 @@ func (consensus *Consensus) commitBlock(blk *types.Block, committedMsg *FBFTMess
// rotateLeader rotates the leader to the next leader in the committee.
// This function must be called with enabled leader rotation.
func (consensus *Consensus) rotateLeader(epoch *big.Int) {
prev := consensus.getLeaderPubKey()
bc := consensus.Blockchain()
curNumber := bc.CurrentHeader().Number().Uint64()
utils.Logger().Info().Msgf("[Rotating leader] epoch: %v rotation:%v numblocks:%d", epoch.Uint64(), bc.Config().IsLeaderRotation(epoch), bc.Config().LeaderRotationBlocksCount)
leader := consensus.getLeaderPubKey()
for i := 0; i < bc.Config().LeaderRotationBlocksCount; i++ {
header := bc.GetHeaderByNumber(curNumber - uint64(i))
if header == nil {
return
}
// Previous epoch, we should not change leader.
if header.Epoch().Uint64() != epoch.Uint64() {
return
}
// Check if the same leader.
pub, err := bc.GetLeaderPubKeyFromCoinbase(header)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to get leader public key from coinbase")
return
}
if !pub.Object.IsEqual(leader.Object) {
// Another leader.
return
}
var (
bc = consensus.Blockchain()
prev = consensus.getLeaderPubKey()
leader = consensus.getLeaderPubKey()
)
utils.Logger().Info().Msgf("[Rotating leader] epoch: %v rotation:%v external rotation %v", epoch.Uint64(), bc.Config().IsLeaderRotation(epoch), bc.Config().IsLeaderRotationExternalValidatorsAllowed(epoch, consensus.ShardID))
ss, err := bc.ReadShardState(epoch)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to read shard state")
return
}
committee, err := ss.FindCommitteeByID(consensus.ShardID)
if err != nil {
utils.Logger().Error().Err(err).Msg("Failed to find committee")
return
}
slotsCount := len(committee.Slots)
blocksPerEpoch := shard.Schedule.InstanceForEpoch(epoch).BlocksPerEpoch()
if blocksPerEpoch == 0 {
utils.Logger().Error().Msg("[Rotating leader] blocks per epoch is 0")
return
}
if slotsCount == 0 {
utils.Logger().Error().Msg("[Rotating leader] slots count is 0")
return
}
numBlocksProducedByLeader := blocksPerEpoch / uint64(slotsCount)
rest := blocksPerEpoch % uint64(slotsCount)
const minimumBlocksForLeaderInRow = 3
if numBlocksProducedByLeader < minimumBlocksForLeaderInRow {
// mine no less than 3 blocks in a row
numBlocksProducedByLeader = minimumBlocksForLeaderInRow
}
type stored struct {
pub []byte
epoch uint64
count uint64
shifts uint64 // count how much changes validator per epoch
}
var s stored
s.pub, s.epoch, s.count, s.shifts, _ = bc.LeaderRotationMeta()
if !bytes.Equal(leader.Bytes[:], s.pub) {
// Another leader.
return
}
// if it is the first validator which produce blocks, then it should produce `rest` blocks too.
if s.shifts == 0 {
numBlocksProducedByLeader += rest
}
if s.count < numBlocksProducedByLeader {
// Not enough blocks produced by the leader.
return
}
// Passed all checks, we can change leader.
// NthNext will move the leader to the next leader in the committee.
// It does not know anything about external or internal validators.
var (
wasFound bool
next *bls.PublicKeyWrapper
)
if consensus.ShardID == shard.BeaconChainShardID {
wasFound, next = consensus.Decider.NthNextHmy(shard.Schedule.InstanceForEpoch(epoch), leader, 1)
} else {
if bc.Config().IsLeaderRotationExternalValidatorsAllowed(epoch, consensus.ShardID) {
wasFound, next = consensus.Decider.NthNext(leader, 1)
} else {
wasFound, next = consensus.Decider.NthNextHmy(shard.Schedule.InstanceForEpoch(epoch), leader, 1)
}
if !wasFound {
utils.Logger().Error().Msg("Failed to get next leader")

@ -63,9 +63,8 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) {
go func() {
// Best effort check, no need to error out.
_, err := consensus.ValidateNewBlock(recvMsg)
if err == nil {
consensus.getLogger().Info().
consensus.GetLogger().Info().
Msg("[Announce] Block verified")
}
}()

@ -203,13 +203,13 @@ func (consensus *Consensus) getNextLeaderKey(viewID uint64) *bls.PublicKeyWrappe
var wasFound bool
var next *bls.PublicKeyWrapper
if blockchain != nil && blockchain.Config().IsLeaderRotation(epoch) {
if consensus.ShardID == shard.BeaconChainShardID {
wasFound, next = consensus.Decider.NthNextHmy(
shard.Schedule.InstanceForEpoch(epoch),
if blockchain.Config().IsLeaderRotationExternalValidatorsAllowed(epoch, consensus.ShardID) {
wasFound, next = consensus.Decider.NthNext(
lastLeaderPubKey,
gap)
} else {
wasFound, next = consensus.Decider.NthNext(
wasFound, next = consensus.Decider.NthNextHmy(
shard.Schedule.InstanceForEpoch(epoch),
lastLeaderPubKey,
gap)
}

@ -107,6 +107,8 @@ type BlockChain interface {
//
// After insertion is done, all accumulated events will be fired.
InsertChain(chain types.Blocks, verifyHeaders bool) (int, error)
// LeaderRotationMeta returns the number of continuous blocks by the leader.
LeaderRotationMeta() (publicKeyBytes []byte, epoch, count, shifts uint64, err error)
// BadBlocks returns a list of the last 'bad blocks' that
// the client has seen on the network.
BadBlocks() []BadBlock

@ -114,6 +114,7 @@ const (
validatorListByDelegatorCacheLimit = 128
pendingCrossLinksCacheLimit = 2
blockAccumulatorCacheLimit = 64
leaderPubKeyFromCoinbaseLimit = 8
maxPendingSlashes = 256
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -240,7 +241,7 @@ func newBlockChainWithOptions(
validatorListByDelegatorCache, _ := lru.New(validatorListByDelegatorCacheLimit)
pendingCrossLinksCache, _ := lru.New(pendingCrossLinksCacheLimit)
blockAccumulatorCache, _ := lru.New(blockAccumulatorCacheLimit)
leaderPubKeyFromCoinbase, _ := lru.New(chainConfig.LeaderRotationBlocksCount + 2)
leaderPubKeyFromCoinbase, _ := lru.New(leaderPubKeyFromCoinbaseLimit)
bc := &BlockChainImpl{
chainConfig: chainConfig,
@ -1522,6 +1523,18 @@ func (bc *BlockChainImpl) InsertChain(chain types.Blocks, verifyHeaders bool) (i
n, events, logs, err := bc.insertChain(chain, verifyHeaders)
bc.PostChainEvents(events, logs)
if err == nil {
// there should be only 1 block.
for _, b := range chain {
if b.Epoch().Uint64() > 0 {
err := bc.saveLeaderRotationMeta(b.Header())
if err != nil {
utils.Logger().Error().Err(err).Msg("save leader continuous blocks count error")
return n, err
}
}
}
}
if bc.isInitTiKV() && err != nil {
// if has some error, master writer node will release the permission
_, _ = bc.redisPreempt.Unlock()
@ -1529,6 +1542,47 @@ func (bc *BlockChainImpl) InsertChain(chain types.Blocks, verifyHeaders bool) (i
return n, err
}
func (bc *BlockChainImpl) saveLeaderRotationMeta(h *block.Header) error {
blockPubKey, err := bc.getLeaderPubKeyFromCoinbase(h)
if err != nil {
return err
}
type stored struct {
pub []byte
epoch uint64
count uint64
shifts uint64
}
var s stored
// error is possible here only on the first iteration, so we can ignore it
s.pub, s.epoch, s.count, s.shifts, _ = rawdb.ReadLeaderRotationMeta(bc.db)
// increase counter only if the same leader and epoch
if bytes.Equal(s.pub, blockPubKey.Bytes[:]) && s.epoch == h.Epoch().Uint64() {
s.count++
} else {
s.count = 1
}
// we should increase shifts if the leader is changed.
if !bytes.Equal(s.pub, blockPubKey.Bytes[:]) {
s.shifts++
}
// but set to zero if new
if s.epoch != h.Epoch().Uint64() {
s.shifts = 0
}
err = rawdb.WriteLeaderRotationMeta(bc.db, blockPubKey.Bytes[:], h.Epoch().Uint64(), s.count, s.shifts)
if err != nil {
return err
}
return nil
}
func (bc *BlockChainImpl) LeaderRotationMeta() (publicKeyBytes []byte, epoch, count, shifts uint64, err error) {
return rawdb.ReadLeaderRotationMeta(bc.db)
}
// insertChain will execute the actual chain insertion and event aggregation. The
// only reason this method exists as a separate one is to make locking cleaner
// with deferred statements.

@ -423,3 +423,7 @@ func (a Stub) SyncFromTiKVWriter(newBlkNum uint64, logs []*types.Log) error {
func (a Stub) InitTiKV(conf *harmonyconfig.TiKVConfig) {
return
}
func (a Stub) LeaderRotationMeta() (publicKeyBytes []byte, epoch, count, shifts uint64, err error) {
return nil, 0, 0, 0, errors.Errorf("method LeaderRotationMeta not implemented for %s", a.Name)
}

@ -17,14 +17,17 @@
package rawdb
import (
"encoding/binary"
"encoding/json"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/params"
"github.com/harmony-one/harmony/internal/utils"
"github.com/pkg/errors"
)
// ReadDatabaseVersion retrieves the version number of the database.
@ -192,3 +195,34 @@ func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) {
utils.Logger().Error().Err(err).Msg("Failed to store the eth2 transition status")
}
}
// WriteLeaderRotationMeta writes the leader continuous blocks count to the database.
func WriteLeaderRotationMeta(db DatabaseWriter, leader []byte, epoch uint64, count, shifts uint64) error {
if len(leader) != bls.PublicKeySizeInBytes {
return errors.New("invalid leader public key size")
}
value := make([]byte, bls.PublicKeySizeInBytes+8*3)
copy(value, leader)
binary.LittleEndian.PutUint64(value[len(leader)+8*0:], epoch)
binary.LittleEndian.PutUint64(value[len(leader)+8*1:], count)
binary.LittleEndian.PutUint64(value[len(leader)+8*2:], shifts)
if err := db.Put(leaderContinuousBlocksCountKey(), value); err != nil {
utils.Logger().Error().Err(err).Msg("Failed to store leader continuous blocks count")
return err
}
return nil
}
// ReadLeaderRotationMeta retrieves the leader continuous blocks count from the database.
func ReadLeaderRotationMeta(db DatabaseReader) (pubKeyBytes []byte, epoch, count, shifts uint64, err error) {
data, _ := db.Get(leaderContinuousBlocksCountKey())
if len(data) != bls.PublicKeySizeInBytes+24 {
return nil, 0, 0, 0, errors.New("invalid leader continuous blocks count")
}
pubKeyBytes = data[:bls.PublicKeySizeInBytes]
epoch = binary.LittleEndian.Uint64(data[bls.PublicKeySizeInBytes:])
count = binary.LittleEndian.Uint64(data[bls.PublicKeySizeInBytes+8:])
shifts = binary.LittleEndian.Uint64(data[bls.PublicKeySizeInBytes+16:])
return pubKeyBytes, epoch, count, shifts, nil
}

@ -0,0 +1,32 @@
package rawdb
import (
"testing"
ethRawDB "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/harmony-one/harmony/crypto/bls"
)
func TestLeaderRotationMeta(t *testing.T) {
db := ethRawDB.NewMemoryDatabase()
err := WriteLeaderRotationMeta(db, make([]byte, bls.PublicKeySizeInBytes), 1, 2, 3)
if err != nil {
t.Fatal(err)
}
pub, epoch, count, shifts, err := ReadLeaderRotationMeta(db)
if err != nil {
t.Fatal(err)
}
if len(pub) != bls.PublicKeySizeInBytes {
t.Fatal("invalid leader public key size")
}
if epoch != 1 {
t.Fatal("invalid epoch")
}
if count != 2 {
t.Fatal("invalid count")
}
if shifts != 3 {
t.Fatal("invalid shifts")
}
}

@ -100,6 +100,7 @@ var (
pendingCrosslinkKey = []byte("pendingCL") // prefix for shard last pending crosslink
pendingSlashingKey = []byte("pendingSC") // prefix for shard last pending slashing record
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
continuousBlocksCountKey = []byte("continuous") // key for continuous blocks count
configPrefix = []byte("ethereum-config-") // config prefix for the db
crosslinkPrefix = []byte("cl") // prefix for crosslink
delegatorValidatorListPrefix = []byte("dvl") // prefix for delegator's validator list
@ -285,6 +286,10 @@ func preimageKey(hash common.Hash) []byte {
return append(preimagePrefix, hash.Bytes()...)
}
func leaderContinuousBlocksCountKey() []byte {
return continuousBlocksCountKey
}
// configKey = configPrefix + hash
func configKey(hash common.Hash) []byte {
return append(configPrefix, hash.Bytes()...)

@ -72,8 +72,9 @@ type Instance interface {
// ReshardingEpoch returns a list of Epoch while off-chain resharding happens
ReshardingEpoch() []*big.Int
// Count of blocks per epoch
// BlocksPerEpoch returns the number of blocks per epoch.
BlocksPerEpoch() uint64
// HIP-16: The absolute number of maximum effective slots per shard limit for each validator. 0 means no limit.
SlotsLimit() int

@ -36,250 +36,250 @@ var once sync.Once
var (
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
ChainID: MainnetChainID,
EthCompatibleChainID: EthMainnetShard0ChainID,
EthCompatibleShard0ChainID: EthMainnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(442), // Around Thursday Feb 4th 2020, 10AM PST
CrossTxEpoch: big.NewInt(28),
CrossLinkEpoch: big.NewInt(186),
AggregatedRewardEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
StakingEpoch: big.NewInt(186),
PreStakingEpoch: big.NewInt(185),
QuickUnlockEpoch: big.NewInt(191),
FiveSecondsEpoch: big.NewInt(230),
TwoSecondsEpoch: big.NewInt(366), // Around Tuesday Dec 8th 2020, 8AM PST
SixtyPercentEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC
RedelegationEpoch: big.NewInt(290),
NoEarlyUnlockEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC
VRFEpoch: big.NewInt(631), // Around Wed July 7th 2021
PrevVRFEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
MinDelegation100Epoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionRateEpoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionPromoPeriod: big.NewInt(100),
EPoSBound35Epoch: big.NewInt(631), // Around Wed July 7th 2021
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
DataCopyFixEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
IstanbulEpoch: big.NewInt(314),
ReceiptLogEpoch: big.NewInt(101),
SHA3Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
HIP6And8Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
StakingPrecompileEpoch: big.NewInt(871), // Around Tue Feb 11 2022
ChainIdFixEpoch: big.NewInt(1323), // Around Wed 8 Feb 11:30PM UTC
SlotsLimitedEpoch: big.NewInt(999), // Around Fri, 27 May 2022 09:41:02 UTC with 2s block time
CrossShardXferPrecompileEpoch: big.NewInt(1323), // Around Wed 8 Feb 11:30PM UTC
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: EpochTBD,
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 64,
ValidatorCodeFixEpoch: EpochTBD,
ChainID: MainnetChainID,
EthCompatibleChainID: EthMainnetShard0ChainID,
EthCompatibleShard0ChainID: EthMainnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(442), // Around Thursday Feb 4th 2020, 10AM PST
CrossTxEpoch: big.NewInt(28),
CrossLinkEpoch: big.NewInt(186),
AggregatedRewardEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
StakingEpoch: big.NewInt(186),
PreStakingEpoch: big.NewInt(185),
QuickUnlockEpoch: big.NewInt(191),
FiveSecondsEpoch: big.NewInt(230),
TwoSecondsEpoch: big.NewInt(366), // Around Tuesday Dec 8th 2020, 8AM PST
SixtyPercentEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC
RedelegationEpoch: big.NewInt(290),
NoEarlyUnlockEpoch: big.NewInt(530), // Around Monday Apr 12th 2021, 22:30 UTC
VRFEpoch: big.NewInt(631), // Around Wed July 7th 2021
PrevVRFEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
MinDelegation100Epoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionRateEpoch: big.NewInt(631), // Around Wed July 7th 2021
MinCommissionPromoPeriod: big.NewInt(100),
EPoSBound35Epoch: big.NewInt(631), // Around Wed July 7th 2021
EIP155Epoch: big.NewInt(28),
S3Epoch: big.NewInt(28),
DataCopyFixEpoch: big.NewInt(689), // Around Wed Sept 15th 2021 with 3.5s block time
IstanbulEpoch: big.NewInt(314),
ReceiptLogEpoch: big.NewInt(101),
SHA3Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
HIP6And8Epoch: big.NewInt(725), // Around Mon Oct 11 2021, 19:00 UTC
StakingPrecompileEpoch: big.NewInt(871), // Around Tue Feb 11 2022
ChainIdFixEpoch: big.NewInt(1323), // Around Wed 8 Feb 11:30PM UTC
SlotsLimitedEpoch: big.NewInt(999), // Around Fri, 27 May 2022 09:41:02 UTC with 2s block time
CrossShardXferPrecompileEpoch: big.NewInt(1323), // Around Wed 8 Feb 11:30PM UTC
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: EpochTBD,
LeaderRotationExternalNonBeaconLeaders: EpochTBD,
LeaderRotationExternalBeaconLeaders: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
}
// TestnetChainConfig contains the chain parameters to run a node on the harmony test network.
TestnetChainConfig = &ChainConfig{
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetShard0ChainID,
EthCompatibleShard0ChainID: EthTestnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(2),
SixtyPercentEpoch: big.NewInt(2),
RedelegationEpoch: big.NewInt(2),
NoEarlyUnlockEpoch: big.NewInt(2),
VRFEpoch: big.NewInt(2),
PrevVRFEpoch: big.NewInt(2),
MinDelegation100Epoch: big.NewInt(2),
MinCommissionRateEpoch: big.NewInt(2),
MinCommissionPromoPeriod: big.NewInt(2),
EPoSBound35Epoch: big.NewInt(2),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(2),
StakingPrecompileEpoch: big.NewInt(2),
SlotsLimitedEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
CrossShardXferPrecompileEpoch: big.NewInt(2),
AllowlistEpoch: big.NewInt(2),
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 64,
FeeCollectEpoch: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetShard0ChainID,
EthCompatibleShard0ChainID: EthTestnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(2),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(2),
SixtyPercentEpoch: big.NewInt(2),
RedelegationEpoch: big.NewInt(2),
NoEarlyUnlockEpoch: big.NewInt(2),
VRFEpoch: big.NewInt(2),
PrevVRFEpoch: big.NewInt(2),
MinDelegation100Epoch: big.NewInt(2),
MinCommissionRateEpoch: big.NewInt(2),
MinCommissionPromoPeriod: big.NewInt(2),
EPoSBound35Epoch: big.NewInt(2),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(2),
StakingPrecompileEpoch: big.NewInt(2),
SlotsLimitedEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
CrossShardXferPrecompileEpoch: big.NewInt(2),
AllowlistEpoch: big.NewInt(2),
LeaderRotationExternalNonBeaconLeaders: EpochTBD,
LeaderRotationExternalBeaconLeaders: EpochTBD,
FeeCollectEpoch: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
}
// PangaeaChainConfig contains the chain parameters for the Pangaea network.
// All features except for CrossLink are enabled at launch.
PangaeaChainConfig = &ChainConfig{
ChainID: PangaeaChainID,
EthCompatibleChainID: EthPangaeaShard0ChainID,
EthCompatibleShard0ChainID: EthPangaeaShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2), // same as staking
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 64,
FeeCollectEpoch: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
ChainID: PangaeaChainID,
EthCompatibleChainID: EthPangaeaShard0ChainID,
EthCompatibleShard0ChainID: EthPangaeaShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(0),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2), // same as staking
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
LeaderRotationExternalNonBeaconLeaders: EpochTBD,
LeaderRotationExternalBeaconLeaders: EpochTBD,
FeeCollectEpoch: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
}
// PartnerChainConfig contains the chain parameters for the Partner network.
// This is the Devnet config
PartnerChainConfig = &ChainConfig{
ChainID: PartnerChainID,
EthCompatibleChainID: EthPartnerShard0ChainID,
EthCompatibleShard0ChainID: EthPartnerShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(4),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: big.NewInt(574),
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 64,
ValidatorCodeFixEpoch: EpochTBD,
ChainID: PartnerChainID,
EthCompatibleChainID: EthPartnerShard0ChainID,
EthCompatibleShard0ChainID: EthPartnerShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(4),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: big.NewInt(574),
LeaderRotationExternalNonBeaconLeaders: EpochTBD,
LeaderRotationExternalBeaconLeaders: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
}
// StressnetChainConfig contains the chain parameters for the Stress test network.
// All features except for CrossLink are enabled at launch.
StressnetChainConfig = &ChainConfig{
ChainID: StressnetChainID,
EthCompatibleChainID: EthStressnetShard0ChainID,
EthCompatibleShard0ChainID: EthStressnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(10),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: EpochTBD,
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 64,
ValidatorCodeFixEpoch: EpochTBD,
ChainID: StressnetChainID,
EthCompatibleChainID: EthStressnetShard0ChainID,
EthCompatibleShard0ChainID: EthStressnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(1),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: big.NewInt(10),
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: big.NewInt(0),
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
FeeCollectEpoch: EpochTBD,
LeaderRotationExternalNonBeaconLeaders: EpochTBD,
LeaderRotationExternalBeaconLeaders: EpochTBD,
ValidatorCodeFixEpoch: EpochTBD,
}
// LocalnetChainConfig contains the chain parameters to run for local development.
LocalnetChainConfig = &ChainConfig{
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetShard0ChainID,
EthCompatibleShard0ChainID: EthTestnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(0),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
LeaderRotationEpoch: EpochTBD,
LeaderRotationBlocksCount: 5,
FeeCollectEpoch: big.NewInt(5),
ValidatorCodeFixEpoch: EpochTBD,
ChainID: TestnetChainID,
EthCompatibleChainID: EthTestnetShard0ChainID,
EthCompatibleShard0ChainID: EthTestnetShard0ChainID,
EthCompatibleEpoch: big.NewInt(0),
CrossTxEpoch: big.NewInt(0),
CrossLinkEpoch: big.NewInt(2),
AggregatedRewardEpoch: big.NewInt(3),
StakingEpoch: big.NewInt(2),
PreStakingEpoch: big.NewInt(0),
QuickUnlockEpoch: big.NewInt(0),
FiveSecondsEpoch: big.NewInt(0),
TwoSecondsEpoch: big.NewInt(0),
SixtyPercentEpoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
RedelegationEpoch: big.NewInt(0),
NoEarlyUnlockEpoch: big.NewInt(0),
VRFEpoch: big.NewInt(0),
PrevVRFEpoch: big.NewInt(0),
MinDelegation100Epoch: big.NewInt(0),
MinCommissionRateEpoch: big.NewInt(0),
MinCommissionPromoPeriod: big.NewInt(10),
EPoSBound35Epoch: big.NewInt(0),
EIP155Epoch: big.NewInt(0),
S3Epoch: big.NewInt(0),
DataCopyFixEpoch: big.NewInt(0),
IstanbulEpoch: big.NewInt(0),
ReceiptLogEpoch: big.NewInt(0),
SHA3Epoch: big.NewInt(0),
HIP6And8Epoch: EpochTBD, // Never enable it for localnet as localnet has no external validator setup
StakingPrecompileEpoch: big.NewInt(2),
ChainIdFixEpoch: big.NewInt(0),
SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16
CrossShardXferPrecompileEpoch: big.NewInt(1),
AllowlistEpoch: EpochTBD,
LeaderRotationExternalNonBeaconLeaders: big.NewInt(5),
LeaderRotationExternalBeaconLeaders: big.NewInt(6),
FeeCollectEpoch: big.NewInt(5),
ValidatorCodeFixEpoch: EpochTBD,
}
// AllProtocolChanges ...
@ -319,8 +319,8 @@ var (
big.NewInt(0), // SlotsLimitedEpoch
big.NewInt(1), // CrossShardXferPrecompileEpoch
big.NewInt(0), // AllowlistEpoch
big.NewInt(1), // LeaderRotationEpoch
64, // LeaderRotationBlocksCount
big.NewInt(1), // LeaderRotationExternalNonBeaconLeaders
big.NewInt(1), // LeaderRotationExternalBeaconLeaders
big.NewInt(0), // FeeCollectEpoch
big.NewInt(0), // ValidatorCodeFixEpoch
}
@ -362,8 +362,8 @@ var (
big.NewInt(0), // SlotsLimitedEpoch
big.NewInt(1), // CrossShardXferPrecompileEpoch
big.NewInt(0), // AllowlistEpoch
big.NewInt(1), // LeaderRotationEpoch
64, // LeaderRotationBlocksCount
big.NewInt(1), // LeaderRotationExternalNonBeaconLeaders
big.NewInt(1), // LeaderRotationExternalBeaconLeaders
big.NewInt(0), // FeeCollectEpoch
big.NewInt(0), // ValidatorCodeFixEpoch
}
@ -505,9 +505,9 @@ type ChainConfig struct {
// AllowlistEpoch is the first epoch to support allowlist of HIP18
AllowlistEpoch *big.Int
LeaderRotationEpoch *big.Int `json:"leader-rotation-epoch,omitempty"`
LeaderRotationExternalNonBeaconLeaders *big.Int `json:"leader-rotation-external-non-beacon-leaders,omitempty"`
LeaderRotationBlocksCount int `json:"leader-rotation-blocks-count,omitempty"`
LeaderRotationExternalBeaconLeaders *big.Int `json:"leader-rotation-external-beacon-leaders,omitempty"`
// FeeCollectEpoch is the first epoch that enables txn fees to be collected into the community-managed account.
// It should >= StakingEpoch.
@ -725,7 +725,17 @@ func (c *ChainConfig) IsAllowlistEpoch(epoch *big.Int) bool {
}
func (c *ChainConfig) IsLeaderRotation(epoch *big.Int) bool {
return isForked(c.LeaderRotationEpoch, epoch)
return isForked(c.LeaderRotationExternalNonBeaconLeaders, epoch)
}
func (c *ChainConfig) IsLeaderRotationExternalValidatorsAllowed(epoch *big.Int, shardID uint32) bool {
if !c.IsLeaderRotation(epoch) {
return false
}
if shardID == 0 {
return isForked(c.LeaderRotationExternalBeaconLeaders, epoch)
}
return true
}
// IsFeeCollectEpoch determines whether Txn Fees will be collected into the community-managed account.

@ -202,6 +202,12 @@ func (d Dec) Copy() Dec {
}
}
func (d Dec) Div(d2 Dec) Dec {
return Dec{
new(big.Int).Div(d.Int, d2.Int),
}
}
// IsNil ...
func (d Dec) IsNil() bool { return d.Int == nil } // is decimal nil
// IsZero ...

@ -368,3 +368,27 @@ func TestDecCeil(t *testing.T) {
require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input)
}
}
func TestDiv(t *testing.T) {
tests := []struct {
d1, d2, exp Dec
}{
{mustNewDecFromStr(t, "0"), mustNewDecFromStr(t, "1"), ZeroDec()},
{mustNewDecFromStr(t, "1"), mustNewDecFromStr(t, "1"), NewDec(1)},
{mustNewDecFromStr(t, "1"), mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "0.5")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "1"), NewDec(2)},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "3"), mustNewDecFromStr(t, "0.666666666666666667")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "4"), mustNewDecFromStr(t, "0.5")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "5"), mustNewDecFromStr(t, "0.4")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "6"), mustNewDecFromStr(t, "0.333333333333333333")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "7"), mustNewDecFromStr(t, "0.285714285714285714")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "8"), mustNewDecFromStr(t, "0.25")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "9"), mustNewDecFromStr(t, "0.222222222222222222")},
{mustNewDecFromStr(t, "2"), mustNewDecFromStr(t, "10"), mustNewDecFromStr(t, "0.2")},
}
for i, tc := range tests {
res := tc.d1.Quo(tc.d2)
require.True(t, res.Equal(tc.exp), "unexpected result for test case %d, input: %s %s %s", i, tc.d1, tc.d2, tc.exp)
}
}

Loading…
Cancel
Save