Merge pull request #1927 from rlan35/staking_devnet_fixes

Add epoch number in shard state for use of beacon epoch sync
pull/1931/head
Rongjian Lan 5 years ago committed by GitHub
commit 1f5ca9c661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      api/proto/node/node.go
  2. 4
      api/service/explorer/service.go
  3. 6
      api/service/syncing/syncing.go
  4. 6
      block/v0/header.go
  5. 6
      block/v1/header.go
  6. 6
      block/v2/header.go
  7. 6
      block/v3/header.go
  8. 9
      consensus/consensus_v2.go
  9. 2
      consensus/engine/consensus_engine.go
  10. 94
      core/blockchain.go
  11. 2
      core/chain_makers.go
  12. 4
      core/genesis.go
  13. 20
      core/rawdb/accessors_chain.go
  14. 2
      core/state_transition.go
  15. 15
      core/types/block.go
  16. 10
      hmy/api_backend.go
  17. 4
      internal/chain/engine.go
  18. 5
      internal/chain/reward.go
  19. 2
      internal/hmyapi/backend.go
  20. 2
      internal/hmyapi/blockchain.go
  21. 31
      node/node_cross_shard.go
  22. 2
      node/node_explorer.go
  23. 10
      node/node_genesis.go
  24. 2
      node/node_handler.go
  25. 18
      node/node_newblock.go
  26. 2
      node/node_resharding.go
  27. 47
      node/worker/worker.go
  28. 56
      shard/committee/assignment.go
  29. 93
      shard/shard_state.go
  30. 8
      shard/shard_state_test.go
  31. 26
      staking/types/validator.go

@ -174,6 +174,9 @@ func ConstructCrossLinkMessage(bc engine.ChainReader, headers []*block.Header) [
crosslinks := []types.CrossLink{}
for _, header := range headers {
if header.Number().Uint64() <= 1 || !bc.Config().IsCrossLink(header.Epoch()) {
continue
}
parentHeader := bc.GetHeaderByHash(header.ParentHash())
if parentHeader == nil {
continue

@ -269,7 +269,7 @@ func (s *Service) GetExplorerBlocks(w http.ResponseWriter, r *http.Request) {
if accountBlocks[id-1] != nil {
state, err := accountBlocks[id-1].Header().GetShardState()
if err == nil {
for _, shardCommittee := range state {
for _, shardCommittee := range state.Shards {
if shardCommittee.ShardID == accountBlock.ShardID() {
committee = &shardCommittee
break
@ -392,7 +392,7 @@ func (s *ServiceAPI) GetExplorerBlocks(ctx context.Context, from, to, page, offs
if accountBlocks[id-1] != nil {
state, err := accountBlocks[id-1].Header().GetShardState()
if err == nil {
for _, shardCommittee := range state {
for _, shardCommittee := range state.Shards {
if shardCommittee.ShardID == accountBlock.ShardID() {
committee = &shardCommittee
break

@ -114,10 +114,14 @@ type StateSync struct {
}
func (ss *StateSync) purgeAllBlocksFromCache() {
ss.lastMileMux.Lock()
ss.lastMileBlocks = nil
ss.lastMileMux.Unlock()
ss.syncMux.Lock()
defer ss.syncMux.Unlock()
ss.commonBlocks = make(map[int]*types.Block)
ss.lastMileBlocks = nil
ss.syncConfig.ForEachPeer(func(configPeer *SyncPeerConfig) (brk bool) {
configPeer.blockHashes = nil
configPeer.newBlocks = nil

@ -418,7 +418,11 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger {
// GetShardState returns the deserialized shard state object.
func (h *Header) GetShardState() (shard.State, error) {
return shard.DecodeWrapper(h.ShardState())
state, err := shard.DecodeWrapper(h.ShardState())
if err != nil {
return shard.State{}, err
}
return *state, nil
}
// Copy returns a copy of the given header.

@ -406,7 +406,11 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger {
// GetShardState returns the deserialized shard state object.
func (h *Header) GetShardState() (shard.State, error) {
return shard.DecodeWrapper(h.ShardState())
state, err := shard.DecodeWrapper(h.ShardState())
if err != nil {
return shard.State{}, err
}
return *state, nil
}
// Copy returns a copy of the given header.

@ -402,7 +402,11 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger {
// GetShardState returns the deserialized shard state object.
func (h *Header) GetShardState() (shard.State, error) {
return shard.DecodeWrapper(h.ShardState())
state, err := shard.DecodeWrapper(h.ShardState())
if err != nil {
return shard.State{}, err
}
return *state, nil
}
// Copy returns a copy of the given header.

@ -406,7 +406,11 @@ func (h *Header) Logger(logger *zerolog.Logger) *zerolog.Logger {
// GetShardState returns the deserialized shard state object.
func (h *Header) GetShardState() (shard.State, error) {
return shard.DecodeWrapper(h.ShardState())
state, err := shard.DecodeWrapper(h.ShardState())
if err != nil {
return shard.State{}, err
}
return *state, nil
}
// Copy returns a copy of the given header.

@ -215,8 +215,8 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) {
if recvMsg.BlockNum < consensus.blockNum || recvMsg.BlockNum != header.Number().Uint64() {
utils.Logger().Debug().
Uint64("MsgBlockNum", recvMsg.BlockNum).
Uint64("blockNum", consensus.blockNum).
Uint64("hdrBlockNum", header.Number().Uint64()).
Uint64("consensuBlockNum", consensus.blockNum).
Msg("[OnAnnounce] BlockNum does not match")
return
}
@ -789,10 +789,11 @@ func (consensus *Consensus) finalizeCommits() {
consensus.ChainReader.WriteLastCommits(pbftMsg.Payload)
// find correct block content
block := consensus.FBFTLog.GetBlockByHash(consensus.blockHash)
curBlockHash := consensus.blockHash
block := consensus.FBFTLog.GetBlockByHash(curBlockHash)
if block == nil {
utils.Logger().Warn().
Str("blockHash", hex.EncodeToString(consensus.blockHash[:])).
Str("blockHash", hex.EncodeToString(curBlockHash[:])).
Msg("[FinalizeCommits] Cannot find block by hash")
return
}
@ -814,7 +815,7 @@ func (consensus *Consensus) finalizeCommits() {
utils.Logger().Warn().Err(err).Msg("[Finalizing] Cannot send committed message")
} else {
utils.Logger().Info().
Hex("blockHash", consensus.blockHash[:]).
Hex("blockHash", curBlockHash[:]).
Uint64("blockNum", consensus.blockNum).
Msg("[Finalizing] Sent Committed Message")
}

@ -40,7 +40,7 @@ type ChainReader interface {
// ReadShardState retrieves sharding state given the epoch number.
// This api reads the shard state cached or saved on the chaindb.
// Thus, only should be used to read the shard state of the current chain.
ReadShardState(epoch *big.Int) (shard.State, error)
ReadShardState(epoch *big.Int) (*shard.State, error)
// ReadActiveValidatorList retrieves the list of active validators
ReadActiveValidatorList() ([]common.Address, error)

@ -68,7 +68,7 @@ const (
maxTimeFutureBlocks = 30
badBlockLimit = 10
triesInMemory = 128
shardCacheLimit = 4
shardCacheLimit = 10
commitsCacheLimit = 10
epochCacheLimit = 10
randomnessCacheLimit = 10
@ -76,7 +76,7 @@ const (
validatorStatsCacheLimit = 1024
validatorListCacheLimit = 10
validatorListByDelegatorCacheLimit = 1024
pendingCrossLinksCacheLimit = 10
pendingCrossLinksCacheLimit = 2
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
BlockChainVersion = 3
@ -1156,33 +1156,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
return NonStatTy, err
}
// Staking epoch migration. Only Execute once:
// Normally the last block of an epoch should have the same epoch as this block
// In the case beacon chain catch up, it may have a epoch larger than the current epoch
// We need to write the same shard state for this one-off epoch so other readers doesn't break
parentHeader := bc.GetHeaderByHash(header.ParentHash())
if parentHeader != nil && parentHeader.Epoch().Cmp(header.Epoch()) != 0 {
curShardState, err := bc.ReadShardState(parentHeader.Epoch())
if err != nil {
header.Logger(utils.Logger()).Warn().Err(err).Msg("cannot read current shard state")
return NonStatTy, err
}
data, err := rlp.EncodeToBytes(curShardState)
if err != nil {
return NonStatTy, err
}
_, err = bc.WriteShardStateBytes(batch, header.Epoch(), data)
if err != nil {
header.Logger(utils.Logger()).Warn().Err(err).Msg("cannot store shard state")
return NonStatTy, err
}
}
// Find all the active validator addresses and store them in db
allActiveValidators := []common.Address{}
processed := make(map[common.Address]struct{})
for i := range *newShardState {
shard := (*newShardState)[i]
for i := range newShardState.Shards {
shard := newShardState.Shards[i]
for j := range shard.Slots {
slot := shard.Slots[j]
if slot.TotalStake != nil { // For external validator
@ -1219,13 +1197,14 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
// Update voting power of validators for all shards
if block.ShardID() == 0 && len(block.Header().ShardState()) > 0 {
shardState := shard.State{}
if err := rlp.DecodeBytes(block.Header().ShardState(), &shardState); err == nil {
shardState := new(shard.State)
if shardState, err = shard.DecodeWrapper(block.Header().ShardState()); err == nil {
if err = bc.UpdateValidatorVotingPower(shardState); err != nil {
utils.Logger().Err(err)
utils.Logger().Err(err).Msg("[UpdateValidatorVotingPower] Failed to update voting power")
}
} else {
utils.Logger().Err(err)
utils.Logger().Err(err).Msg("[UpdateValidatorVotingPower] Failed to decode shard state")
}
}
@ -2007,10 +1986,10 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript
}
// ReadShardState retrieves sharding state given the epoch number.
func (bc *BlockChain) ReadShardState(epoch *big.Int) (shard.State, error) {
func (bc *BlockChain) ReadShardState(epoch *big.Int) (*shard.State, error) {
cacheKey := string(epoch.Bytes())
if cached, ok := bc.shardStateCache.Get(cacheKey); ok {
shardState := cached.(shard.State)
shardState := cached.(*shard.State)
return shardState, nil
}
shardState, err := rawdb.ReadShardState(bc.db, epoch)
@ -2021,22 +2000,6 @@ func (bc *BlockChain) ReadShardState(epoch *big.Int) (shard.State, error) {
return shardState, nil
}
// WriteShardState saves the given sharding state under the given epoch number.
func (bc *BlockChain) WriteShardState(
epoch *big.Int, shardState shard.State,
) error {
shardState = shardState.DeepCopy()
err := rawdb.WriteShardState(
bc.db, epoch, shardState, bc.Config().IsStaking(epoch),
)
if err != nil {
return err
}
cacheKey := string(epoch.Bytes())
bc.shardStateCache.Add(cacheKey, shardState)
return nil
}
// WriteShardStateBytes saves the given sharding state under the given epoch number.
func (bc *BlockChain) WriteShardStateBytes(db rawdb.DatabaseWriter,
epoch *big.Int, shardState []byte,
@ -2051,7 +2014,7 @@ func (bc *BlockChain) WriteShardStateBytes(db rawdb.DatabaseWriter,
}
cacheKey := string(epoch.Bytes())
bc.shardStateCache.Add(cacheKey, decodeShardState)
return &decodeShardState, nil
return decodeShardState, nil
}
// ReadLastCommits retrieves last commits.
@ -2574,9 +2537,8 @@ func (bc *BlockChain) ReadValidatorSnapshot(addr common.Address) (*staking.Valid
return rawdb.ReadValidatorSnapshot(bc.db, addr)
}
// WriteValidatorSnapshots writes the snapshot of provided list of validators
// Note: this should only be called within the blockchain insertBlock process.
func (bc *BlockChain) WriteValidatorSnapshots(addrs []common.Address) error {
// writeValidatorSnapshots writes the snapshot of provided list of validators
func (bc *BlockChain) writeValidatorSnapshots(addrs []common.Address) error {
// Read all validator's current data
validators := []*staking.ValidatorWrapper{}
for _, addr := range addrs {
@ -2662,11 +2624,15 @@ func (bc *BlockChain) UpdateValidatorUptime(slots shard.SlotList, mask *bls.Mask
}
// UpdateValidatorVotingPower writes the voting power for the committees
func (bc *BlockChain) UpdateValidatorVotingPower(state shard.State) error {
func (bc *BlockChain) UpdateValidatorVotingPower(state *shard.State) error {
if state == nil {
return errors.New("[UpdateValidatorVotingPower] Nil shard state")
}
totalEffectiveStake := make(map[uint32]numeric.Dec)
addrToEffectiveStakes := make(map[common.Address]map[uint32]numeric.Dec)
for _, committee := range state {
for _, committee := range state.Shards {
for _, slot := range committee.Slots {
if slot.TotalStake != nil {
if _, ok := addrToEffectiveStakes[slot.EcdsaAddress]; !ok {
@ -2699,7 +2665,7 @@ func (bc *BlockChain) UpdateValidatorVotingPower(state shard.State) error {
stats = &staking.ValidatorStats{big.NewInt(0), big.NewInt(0), big.NewInt(0), numeric.NewDec(0), numeric.NewDec(0)}
}
stats.AvgVotingPower = addrTotalVotingPower.Quo(numeric.NewDec(int64(len(state))))
stats.AvgVotingPower = addrTotalVotingPower.Quo(numeric.NewDec(int64(len(state.Shards))))
stats.TotalEffectiveStake = addrTotalEffectiveStake
err = rawdb.WriteValidatorStats(batch, addr, stats)
@ -2714,9 +2680,8 @@ func (bc *BlockChain) UpdateValidatorVotingPower(state shard.State) error {
return nil
}
// DeleteValidatorSnapshots deletes the snapshot staking information of given validator address
// Note: this should only be called within the blockchain insertBlock process.
func (bc *BlockChain) DeleteValidatorSnapshots(addrs []common.Address) error {
// deleteValidatorSnapshots deletes the snapshot staking information of given validator address
func (bc *BlockChain) deleteValidatorSnapshots(addrs []common.Address) error {
batch := bc.db.NewBatch()
for i := range addrs {
rawdb.DeleteValidatorSnapshot(batch, addrs[i])
@ -2739,12 +2704,12 @@ func (bc *BlockChain) UpdateValidatorSnapshots() error {
}
// TODO: enable this once we allow validator to delete itself.
//err = bc.DeleteValidatorSnapshots(allValidators)
//err = bc.deleteValidatorSnapshots(allValidators)
//if err != nil {
// return err
//}
if err := bc.WriteValidatorSnapshots(allValidators); err != nil {
if err := bc.writeValidatorSnapshots(allValidators); err != nil {
return err
}
return nil
@ -2817,9 +2782,8 @@ func (bc *BlockChain) ReadDelegationsByDelegator(delegator common.Address) ([]st
return rawdb.ReadDelegationsByDelegator(bc.db, delegator)
}
// WriteDelegationsByDelegator writes the list of validator addresses to database
// Note: this should only be called within the blockchain insertBlock process.
func (bc *BlockChain) WriteDelegationsByDelegator(delegator common.Address, indices []staking.DelegationIndex) error {
// writeDelegationsByDelegator writes the list of validator addresses to database
func (bc *BlockChain) writeDelegationsByDelegator(delegator common.Address, indices []staking.DelegationIndex) error {
err := rawdb.WriteDelegationsByDelegator(bc.db, delegator, indices)
if err != nil {
return err
@ -2893,7 +2857,7 @@ func (bc *BlockChain) BlockRewardAccumulator() (*big.Int, error) {
}
// WriteBlockRewardAccumulator directly writes the BlockRewardAccumulator value
// Note: this should only be called within the blockchain insertBlock process.
// Note: this should only be called once during staking launch.
func (bc *BlockChain) WriteBlockRewardAccumulator(reward *big.Int) error {
return rawdb.WriteBlockRewardAccumulator(bc.db, reward)
}
@ -2938,7 +2902,7 @@ func (bc *BlockChain) addDelegationIndex(delegatorAddress, validatorAddress comm
})
}
}
return bc.WriteDelegationsByDelegator(delegatorAddress, delegations)
return bc.writeDelegationsByDelegator(delegatorAddress, delegations)
}
// ValidatorCandidates returns the up to date validator candidates for next epoch

@ -269,7 +269,7 @@ func (cr *fakeChainReader) GetHeaderByNumber(number uint64) *block.Header
func (cr *fakeChainReader) GetHeaderByHash(hash common.Hash) *block.Header { return nil }
func (cr *fakeChainReader) GetHeader(hash common.Hash, number uint64) *block.Header { return nil }
func (cr *fakeChainReader) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
func (cr *fakeChainReader) ReadShardState(epoch *big.Int) (shard.State, error) { return nil, nil }
func (cr *fakeChainReader) ReadShardState(epoch *big.Int) (*shard.State, error) { return nil, nil }
func (cr *fakeChainReader) ReadActiveValidatorList() ([]common.Address, error) { return nil, nil }
func (cr *fakeChainReader) ValidatorCandidates() []common.Address { return nil }
func (cr *fakeChainReader) ReadValidatorInformation(addr common.Address) (*staking.ValidatorWrapper, error) {

@ -29,8 +29,6 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/rlp"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/internal/params"
@ -249,7 +247,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
}
}
root := statedb.IntermediateRoot(false)
shardStateBytes, err := rlp.EncodeToBytes(g.ShardState)
shardStateBytes, err := shard.EncodeWrapper(g.ShardState, false)
if err != nil {
utils.Logger().Error().Msg("failed to rlp-serialize genesis shard state")
os.Exit(1)

@ -417,7 +417,7 @@ func FindCommonAncestor(db DatabaseReader, a, b *block.Header) *block.Header {
// ReadShardState retrieves sharding state.
func ReadShardState(
db DatabaseReader, epoch *big.Int,
) (shard.State, error) {
) (*shard.State, error) {
data, err := db.Get(shardStateKey(epoch))
if err != nil {
return nil, ctxerror.New(MsgNoShardStateFromDB,
@ -433,20 +433,6 @@ func ReadShardState(
return ss, nil
}
// WriteShardState stores sharding state into database.
func WriteShardState(
db DatabaseWriter, epoch *big.Int,
shardState shard.State, isStaking bool,
) error {
data, err := shard.EncodeWrapper(shardState, isStaking)
if err != nil {
return ctxerror.New("cannot encode sharding state",
"epoch", epoch,
).WithCause(err)
}
return WriteShardStateBytes(db, epoch, data)
}
// WriteShardStateBytes stores sharding state into database.
func WriteShardStateBytes(db DatabaseWriter, epoch *big.Int, data []byte) (err error) {
if err = db.Put(shardStateKey(epoch), data); err != nil {
@ -771,10 +757,10 @@ func ReadDelegationsByDelegator(db DatabaseReader, delegator common.Address) ([]
func WriteDelegationsByDelegator(db DatabaseWriter, delegator common.Address, indices []staking.DelegationIndex) error {
bytes, err := rlp.EncodeToBytes(indices)
if err != nil {
utils.Logger().Error().Msg("[WriteDelegationsByDelegator] Failed to encode")
utils.Logger().Error().Msg("[writeDelegationsByDelegator] Failed to encode")
}
if err := db.Put(delegatorValidatorListKey(delegator), bytes); err != nil {
utils.Logger().Error().Msg("[WriteDelegationsByDelegator] Failed to store to database")
utils.Logger().Error().Msg("[writeDelegationsByDelegator] Failed to store to database")
}
return err
}

@ -419,7 +419,7 @@ func (st *StateTransition) applyEditValidatorTx(editValidator *staking.EditValid
return errCommissionRateChangeTooHigh
}
if err := st.state.UpdateStakingInfo(editValidator.ValidatorAddress, wrapper); err != nil {
if err := st.state.UpdateStakingInfo(wrapper.Address, wrapper); err != nil {
return err
}
return nil

@ -38,7 +38,6 @@ import (
v3 "github.com/harmony-one/harmony/block/v3"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
staking "github.com/harmony-one/harmony/staking/types"
"github.com/harmony-one/taggedrlp"
"github.com/pkg/errors"
@ -593,20 +592,6 @@ func (b *Block) AddVdf(vdf []byte) {
b.header.SetVdf(vdf)
}
// AddShardState add shardState into block header
func (b *Block) AddShardState(shardState shard.State) error {
// Make a copy because State.Hash() internally sorts entries.
// Store the sorted copy.
shardState = append(shardState[:0:0], shardState...)
b.header.SetShardStateHash(shardState.Hash())
data, err := rlp.EncodeToBytes(shardState)
if err != nil {
return err
}
b.header.SetShardState(data)
return nil
}
// Logger returns a sub-logger with block contexts added.
func (b *Block) Logger(logger *zerolog.Logger) *zerolog.Logger {
return b.header.Logger(logger)

@ -247,7 +247,7 @@ func (b *APIBackend) GetValidators(epoch *big.Int) (*shard.Committee, error) {
if err != nil {
return nil, err
}
for _, committee := range state {
for _, committee := range state.Shards {
if committee.ShardID == b.GetShardID() {
return &committee, nil
}
@ -364,10 +364,6 @@ func (b *APIBackend) GetValidatorSelfDelegation(addr common.Address) *big.Int {
}
// GetShardState ...
func (b *APIBackend) GetShardState() (shard.State, error) {
state, err := b.hmy.BlockChain().ReadShardState(b.hmy.BlockChain().CurrentHeader().Epoch())
if err != nil {
return nil, err
}
return state, nil
func (b *APIBackend) GetShardState() (*shard.State, error) {
return b.hmy.BlockChain().ReadShardState(b.hmy.BlockChain().CurrentHeader().Epoch())
}

@ -235,7 +235,7 @@ func (e *engineImpl) Finalize(
func QuorumForBlock(
chain engine.ChainReader, h *block.Header, reCalculate bool,
) (quorum int, err error) {
var ss shard.State
ss := new(shard.State)
if reCalculate {
ss, _ = committee.WithStakingEnabled.Compute(h.Epoch(), chain)
} else {
@ -297,7 +297,7 @@ func (e *engineImpl) VerifyHeaderWithSignature(chain engine.ChainReader, header
// GetPublicKeys finds the public keys of the committee that signed the block header
func GetPublicKeys(chain engine.ChainReader, header *block.Header, reCalculate bool) ([]*bls.PublicKey, error) {
var shardState shard.State
shardState := new(shard.State)
var err error
if reCalculate {
shardState, _ = committee.WithStakingEnabled.Compute(header.Epoch(), chain)

@ -4,8 +4,6 @@ import (
"math/big"
"sort"
"github.com/harmony-one/harmony/shard/committee"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/bls/ffi/go/bls"
@ -258,9 +256,6 @@ func AccumulateRewards(
for i := range crossLinks {
cxLink := crossLinks[i]
shardState, err := bc.ReadShardState(cxLink.Epoch())
if !bc.Config().IsStaking(cxLink.Epoch()) {
shardState, err = committee.WithStakingEnabled.Compute(cxLink.Epoch(), bc)
}
if err != nil {
return err

@ -80,7 +80,7 @@ type Backend interface {
GetDelegationsByValidator(validator common.Address) []*staking.Delegation
GetDelegationsByDelegator(delegator common.Address) ([]common.Address, []*staking.Delegation)
GetValidatorSelfDelegation(addr common.Address) *big.Int
GetShardState() (shard.State, error)
GetShardState() (*shard.State, error)
}
// GetAPIs returns all the APIs.

@ -523,7 +523,7 @@ func (s *PublicBlockChainAPI) GetValidatorInformation(ctx context.Context, addre
if err == nil {
blsKeyToShardID := make(map[shard.BlsPublicKey]uint32)
for _, committee := range shardState {
for _, committee := range shardState.Shards {
for _, slot := range committee.Slots {
blsKeyToShardID[slot.BlsPublicKey] = committee.ShardID
}

@ -156,12 +156,7 @@ func (node *Node) ProcessCrossLinkMessage(msgPayload []byte) {
utils.Logger().Debug().
Msgf("[ProcessingCrossLink] Crosslink going to propose: %d", len(crosslinks))
for i, cl := range crosslinks {
if cl.Number() == nil || cl.Epoch().Cmp(node.Blockchain().Config().CrossLinkEpoch) < 0 {
utils.Logger().Debug().
Msgf("[ProcessingCrossLink] Crosslink %d skipped: %v", i, cl)
continue
}
for _, cl := range crosslinks {
exist, err := node.Blockchain().ReadCrossLink(cl.ShardID(), cl.Number().Uint64())
if err == nil && exist != nil {
// TODO: leader add double sign checking
@ -170,13 +165,12 @@ func (node *Node) ProcessCrossLinkMessage(msgPayload []byte) {
continue
}
err = node.VerifyCrossLink(cl)
if err != nil {
utils.Logger().Error().
Err(err).
Msgf("[ProcessingCrossLink] Failed to verify new cross link for shardID %d, blockNum %d", cl.ShardID(), cl.Number())
if err = node.VerifyCrossLink(cl); err != nil {
utils.Logger().Debug().
Msgf("[ProcessingCrossLink] Failed to verify new cross link for blockNum %d epochNum %d shard %d skipped: %v", cl.BlockNum(), cl.Epoch().Uint64(), cl.ShardID(), cl)
continue
}
candidates = append(candidates, cl)
utils.Logger().Debug().
Msgf("[ProcessingCrossLink] committing for shardID %d, blockNum %d", cl.ShardID(), cl.Number().Uint64())
@ -228,8 +222,17 @@ func (node *Node) verifyIncomingReceipts(block *types.Block) error {
// VerifyCrossLink verifies the header is valid
func (node *Node) VerifyCrossLink(cl types.CrossLink) error {
if node.Blockchain().ShardID() != shard.BeaconChainShardID {
return ctxerror.New("Shard chains should not verify cross links")
}
// TODO: add fork choice rule
if cl.BlockNum() <= 1 {
return ctxerror.New("CrossLink BlockNumber should greater than 1")
}
if node.Blockchain().Config().IsCrossLink(cl.Epoch()) {
return ctxerror.New("CrossLink Epoch should >= crosslink epoch", "crossLinkEpoch", node.Blockchain().Config().CrossLinkEpoch)
}
// Verify signature of the new cross link header
// TODO: check whether to recalculate shard state
@ -255,10 +258,6 @@ func (node *Node) VerifyCrossLink(cl types.CrossLink) error {
return ctxerror.New("[CrossLink] cannot convert BLS public key", "shardID", cl.ShardID(), "blockNum", cl.BlockNum()).WithCause(err)
}
if cl.BlockNum() <= 1 {
return ctxerror.New("CrossLink BlockNumber should greater than 1")
}
mask, err := bls_cosi.NewMask(committerKeys, nil)
if err != nil {
return ctxerror.New("cannot create group sig mask", "shardID", cl.ShardID(), "blockNum", cl.BlockNum()).WithCause(err)

@ -192,7 +192,7 @@ func (node *Node) CommitCommittee() {
utils.Logger().Error().Err(err).Msg("[Explorer] Error reading shard state")
continue
}
for _, committee := range state {
for _, committee := range state.Shards {
if committee.ShardID == curBlock.ShardID() {
utils.Logger().Debug().Msg("[Explorer] Dumping committee")
err := explorer.GetStorageInstance(node.SelfPeer.IP, node.SelfPeer.Port, false).DumpCommittee(curBlock.ShardID(), curBlock.Epoch().Uint64(), committee)

@ -48,20 +48,24 @@ func (gi *genesisInitializer) InitChainDB(db ethdb.Database, shardID uint32) err
shardState, _ := committee.WithStakingEnabled.Compute(
big.NewInt(core.GenesisEpoch), nil,
)
if shardState == nil {
return errors.New("failed to create genesis shard state")
}
if shardID != shard.BeaconChainShardID {
// store only the local shard for shard chains
c := shardState.FindCommitteeByID(shardID)
if c == nil {
return errors.New("cannot find local shard in genesis")
}
shardState = shard.State{*c}
shardState = &shard.State{nil, []shard.Committee{*c}}
}
gi.node.SetupGenesisBlock(db, shardID, shardState)
return nil
}
// SetupGenesisBlock sets up a genesis blockchain.
func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardState shard.State) {
func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardState *shard.State) {
utils.Logger().Info().Interface("shardID", shardID).Msg("setting up a brand new chain database")
if shardID == node.NodeConfig.ShardID {
node.isFirstTime = true
@ -102,7 +106,7 @@ func (node *Node) SetupGenesisBlock(db ethdb.Database, shardID uint32, myShardSt
ShardID: shardID,
GasLimit: params.GenesisGasLimit,
ShardStateHash: myShardState.Hash(),
ShardState: myShardState.DeepCopy(),
ShardState: *myShardState.DeepCopy(),
Timestamp: 1561734000, // GMT: Friday, June 28, 2019 3:00:00 PM. PST: Friday, June 28, 2019 8:00:00 AM
ExtraData: []byte("Harmony for One and All. Open Consensus for 10B."),
}

@ -346,7 +346,7 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block, commitSigAndBit
if node.NodeConfig.ShardID == 0 {
node.BroadcastNewBlock(newBlock)
}
if node.NodeConfig.ShardID != shard.BeaconChainShardID && newBlock.Epoch().Cmp(node.Blockchain().Config().CrossLinkEpoch) >= 0 {
if node.NodeConfig.ShardID != shard.BeaconChainShardID && node.Blockchain().Config().IsCrossLink(newBlock.Epoch()) {
node.BroadcastCrossLink(newBlock)
}
node.BroadcastCXReceipts(newBlock, commitSigAndBitmap)

@ -5,6 +5,8 @@ import (
"strings"
"time"
"github.com/harmony-one/harmony/shard"
"github.com/harmony-one/harmony/core/rawdb"
types2 "github.com/harmony-one/harmony/staking/types"
@ -80,13 +82,6 @@ func (node *Node) WaitForConsensusReadyV2(readySignal chan struct{}, stopChan ch
func (node *Node) proposeNewBlock() (*types.Block, error) {
node.Worker.UpdateCurrent()
// Prepare shard state
// NOTE: this will potentially override shard chain's epoch to beacon chain's epoch during staking migration period.
// So this needs to be executed early on.
shardState, err := node.Worker.SuperCommitteeForNextEpoch(
node.Consensus.ShardID, node.Beaconchain(),
)
// Update worker's current header and state data in preparation to propose/process new transactions
coinbase := node.Consensus.SelfAddress
@ -139,6 +134,9 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
if err == nil {
for _, pending := range allPending {
if err = node.VerifyCrossLink(pending); err != nil {
continue
}
exist, err := node.Blockchain().ReadCrossLink(pending.ShardID(), pending.BlockNum())
if err == nil || exist != nil {
continue
@ -151,7 +149,11 @@ func (node *Node) proposeNewBlock() (*types.Block, error) {
}
}
if err != nil {
// Prepare shard state
shardState := new(shard.State)
if shardState, err = node.Worker.SuperCommitteeForNextEpoch(
node.Consensus.ShardID, node.Beaconchain(),
); err != nil {
return nil, err
}

@ -69,7 +69,7 @@ func findRoleInShardState(
key *bls.PublicKey, state shard.State,
) (shardID uint32, isLeader bool) {
keyBytes := key.Serialize()
for idx, shard := range state {
for idx, shard := range state.Shards {
for nodeIdx, nodeID := range shard.Slots {
if bytes.Compare(nodeID.BlsPublicKey[:], keyBytes) == 0 {
return uint32(idx), nodeIdx == 0

@ -262,10 +262,15 @@ func (w *Worker) GetNewEpoch() *big.Int {
parent := w.chain.CurrentBlock()
epoch := new(big.Int).Set(parent.Header().Epoch())
// TODO: Don't depend on sharding state for epoch change.
if len(parent.Header().ShardState()) > 0 && parent.NumberU64() != 0 {
// ... except if parent has a resharding assignment it increases by 1.
epoch = epoch.Add(epoch, common.Big1)
shardState, err := parent.Header().GetShardState()
if err == nil && shardState.Epoch != nil {
// For shard state of staking epochs, the shard state will have an epoch and it will decide the next epoch for following blocks
epoch = new(big.Int).Set(shardState.Epoch)
} else {
if len(parent.Header().ShardState()) > 0 && parent.NumberU64() != 0 {
// if parent has proposed a new shard state it increases by 1, except for genesis block.
epoch = epoch.Add(epoch, common.Big1)
}
}
return epoch
}
@ -289,9 +294,9 @@ func (w *Worker) IncomingReceipts() []*types.CXReceiptsProof {
func (w *Worker) SuperCommitteeForNextEpoch(
shardID uint32,
beacon *core.BlockChain,
) (shard.State, error) {
) (*shard.State, error) {
var (
nextCommittee shard.State
nextCommittee = new(shard.State)
err error
)
switch shardID {
@ -315,15 +320,11 @@ func (w *Worker) SuperCommitteeForNextEpoch(
beaconEpoch, beacon,
)
// Set this block's epoch to be beaconEpoch - 1, so the next block will have beaconEpoch
// This shouldn't be exactly beaconEpoch because the next block will have beaconEpoch + 1
blockEpoch := big.NewInt(0).Set(beaconEpoch).Sub(beaconEpoch, big.NewInt(1))
utils.Logger().Debug().
Uint64("blockNum", w.current.header.Number().Uint64()).
Uint64("myPrevEpoch", w.current.header.Epoch().Uint64()).
Uint64("myCurEpoch", blockEpoch.Uint64()).
Uint64("myCurEpoch", w.current.header.Epoch().Uint64()).
Uint64("beaconEpoch", beaconEpoch.Uint64()).
Msg("Propose new epoch as beacon chain's epoch")
w.current.header.SetEpoch(blockEpoch)
case 0:
// If it's same epoch, no need to propose new shard state (new epoch change)
case -1:
@ -337,20 +338,17 @@ func (w *Worker) SuperCommitteeForNextEpoch(
beaconEpoch, beacon,
)
blockEpoch := big.NewInt(0).Set(beaconEpoch).Sub(beaconEpoch, big.NewInt(1))
utils.Logger().Debug().
Uint64("blockNum", w.current.header.Number().Uint64()).
Uint64("myPrevEpoch", w.current.header.Epoch().Uint64()).
Uint64("myCurEpoch", blockEpoch.Uint64()).
Msg("Propose one-time catch up with beacon chain's epoch")
// Set this block's epoch to be beaconEpoch - 1, so the next block will have beaconEpoch
w.current.header.SetEpoch(blockEpoch)
Uint64("myCurEpoch", w.current.header.Epoch().Uint64()).
Uint64("beaconEpoch", beaconEpoch.Uint64()).
Msg("Propose entering staking along with beacon chain's epoch")
} else {
// If I are not in staking nor has beacon chain proposed a staking-based shard state,
// do pre-staking committee calculation
if shard.Schedule.IsLastBlock(w.current.header.Number().Uint64()) {
nextCommittee, err = committee.WithStakingEnabled.Compute(
new(big.Int).Add(w.current.header.Epoch(), common.Big1),
nextEpoch,
w.chain,
)
}
@ -362,7 +360,7 @@ func (w *Worker) SuperCommitteeForNextEpoch(
}
// FinalizeNewBlock generate a new block for the next consensus round.
func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coinbase common.Address, crossLinks types.CrossLinks, shardState shard.State) (*types.Block, error) {
func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coinbase common.Address, crossLinks types.CrossLinks, shardState *shard.State) (*types.Block, error) {
if len(sig) > 0 && len(signers) > 0 {
sig2 := w.current.header.LastCommitSignature()
copy(sig2[:], sig[:])
@ -391,9 +389,14 @@ func (w *Worker) FinalizeNewBlock(sig []byte, signers []byte, viewID uint64, coi
}
// Shard State
if shardState != nil && len(shardState) != 0 {
if shardState != nil && len(shardState.Shards) != 0 {
w.current.header.SetShardStateHash(shardState.Hash())
shardStateData, err := rlp.EncodeToBytes(shardState)
isStaking := false
if shardState.Epoch != nil && w.config.IsStaking(shardState.Epoch) {
isStaking = true
}
// NOTE: Besides genesis, this is the only place where the shard state is encoded.
shardStateData, err := shard.EncodeWrapper(*shardState, isStaking)
if err == nil {
w.current.header.SetShardState(shardStateData)
} else {

@ -19,8 +19,8 @@ import (
type ValidatorListProvider interface {
Compute(
epoch *big.Int, reader DataProvider,
) (shard.State, error)
ReadFromDB(epoch *big.Int, reader DataProvider) (shard.State, error)
) (*shard.State, error)
ReadFromDB(epoch *big.Int, reader DataProvider) (*shard.State, error)
GetCommitteePublicKeys(committee *shard.Committee) []*bls.PublicKey
}
@ -41,7 +41,7 @@ type ChainReader interface {
// ReadShardState retrieves sharding state given the epoch number.
// This api reads the shard state cached or saved on the chaindb.
// Thus, only should be used to read the shard state of the current chain.
ReadShardState(epoch *big.Int) (shard.State, error)
ReadShardState(epoch *big.Int) (*shard.State, error)
// GetHeader retrieves a block header from the database by hash and number.
GetHeaderByHash(common.Hash) *block.Header
// Config retrieves the blockchain's chain configuration.
@ -61,13 +61,13 @@ var (
WithStakingEnabled Reader = partialStakingEnabled{}
)
func preStakingEnabledCommittee(s shardingconfig.Instance) shard.State {
func preStakingEnabledCommittee(s shardingconfig.Instance) *shard.State {
shardNum := int(s.NumShards())
shardHarmonyNodes := s.NumHarmonyOperatedNodesPerShard()
shardSize := s.NumNodesPerShard()
hmyAccounts := s.HmyAccounts()
fnAccounts := s.FnAccounts()
shardState := shard.State{}
shardState := &shard.State{}
// Shard state needs to be sorted by shard ID
for i := 0; i < shardNum; i++ {
com := shard.Committee{ShardID: uint32(i)}
@ -100,14 +100,14 @@ func preStakingEnabledCommittee(s shardingconfig.Instance) shard.State {
}
com.Slots = append(com.Slots, curNodeID)
}
shardState = append(shardState, com)
shardState.Shards = append(shardState.Shards, com)
}
return shardState
}
func eposStakedCommittee(
s shardingconfig.Instance, stakerReader DataProvider, stakedSlotsCount int,
) (shard.State, error) {
) (*shard.State, error) {
// TODO Nervous about this because overtime the list will become quite large
candidates := stakerReader.ValidatorCandidates()
essentials := map[common.Address]effective.SlotOrder{}
@ -117,6 +117,11 @@ func eposStakedCommittee(
// TODO benchmark difference if went with data structure that sorts on insert
for i := range candidates {
validator, err := stakerReader.ReadValidatorInformation(candidates[i])
if err != nil {
return nil, err
}
if err := validator.SanityCheck(); err != nil {
continue
}
@ -124,9 +129,6 @@ func eposStakedCommittee(
for _, delegation := range validator.Delegations {
validatorStake.Add(validatorStake, delegation.Amount)
}
if err != nil {
return nil, err
}
essentials[validator.Address] = effective.SlotOrder{
validatorStake,
validator.SlotPubKeys,
@ -134,21 +136,23 @@ func eposStakedCommittee(
}
shardCount := int(s.NumShards())
superComm := make(shard.State, shardCount)
shardState := &shard.State{}
shardState.Shards = make([]shard.Committee, shardCount)
hAccounts := s.HmyAccounts()
// Shard state needs to be sorted by shard ID
for i := 0; i < shardCount; i++ {
superComm[i] = shard.Committee{uint32(i), shard.SlotList{}}
shardState.Shards[i] = shard.Committee{uint32(i), shard.SlotList{}}
}
for i := range hAccounts {
spot := i % shardCount
shardID := i % shardCount
pub := &bls.PublicKey{}
pub.DeserializeHexStr(hAccounts[i].BlsPublicKey)
pubKey := shard.BlsPublicKey{}
pubKey.FromLibBLSPublicKey(pub)
superComm[spot].Slots = append(superComm[spot].Slots, shard.Slot{
shardState.Shards[shardID].Slots = append(shardState.Shards[shardID].Slots, shard.Slot{
common2.ParseAddr(hAccounts[i].Address),
pubKey,
nil,
@ -158,7 +162,7 @@ func eposStakedCommittee(
if stakedSlotsCount == 0 {
utils.Logger().Info().Int("slots-for-epos", stakedSlotsCount).
Msg("committe composed only of harmony node")
return superComm, nil
return shardState, nil
}
staked := effective.Apply(essentials, stakedSlotsCount)
@ -170,9 +174,9 @@ func eposStakedCommittee(
}
for i := 0; i < stakedSlotsCount; i++ {
bucket := int(new(big.Int).Mod(staked[i].BlsPublicKey.Big(), shardBig).Int64())
shardID := int(new(big.Int).Mod(staked[i].BlsPublicKey.Big(), shardBig).Int64())
slot := staked[i]
superComm[bucket].Slots = append(superComm[bucket].Slots, shard.Slot{
shardState.Shards[shardID].Slots = append(shardState.Shards[shardID].Slots, shard.Slot{
slot.Address,
staked[i].BlsPublicKey,
&slot.Dec,
@ -180,10 +184,10 @@ func eposStakedCommittee(
}
if c := len(candidates); c != 0 {
utils.Logger().Info().Int("staked-candidates", c).
RawJSON("staked-super-committee", []byte(superComm.JSON())).
RawJSON("staked-super-committee", []byte(shardState.JSON())).
Msg("EPoS based super-committe")
}
return superComm, nil
return shardState, nil
}
// GetCommitteePublicKeys returns the public keys of a shard
@ -201,14 +205,14 @@ func (def partialStakingEnabled) GetCommitteePublicKeys(committee *shard.Committ
func (def partialStakingEnabled) ReadFromDB(
epoch *big.Int, reader DataProvider,
) (newSuperComm shard.State, err error) {
) (newSuperComm *shard.State, err error) {
return reader.ReadShardState(epoch)
}
// ReadFromComputation is single entry point for reading the State of the network
func (def partialStakingEnabled) Compute(
epoch *big.Int, stakerReader DataProvider,
) (newSuperComm shard.State, err error) {
) (newSuperComm *shard.State, err error) {
preStaking := true
if stakerReader != nil {
config := stakerReader.Config()
@ -219,10 +223,18 @@ func (def partialStakingEnabled) Compute(
instance := shard.Schedule.InstanceForEpoch(epoch)
if preStaking {
// Pre-staking shard state doesn't need to set epoch (backward compatible)
return preStakingEnabledCommittee(instance), nil
}
stakedSlots :=
(instance.NumNodesPerShard() - instance.NumHarmonyOperatedNodesPerShard()) *
int(instance.NumShards())
return eposStakedCommittee(instance, stakerReader, stakedSlots)
shardState, err := eposStakedCommittee(instance, stakerReader, stakedSlots)
if err != nil {
return nil, err
}
// Set the epoch of shard state
shardState.Epoch = big.NewInt(0).Set(epoch)
return shardState, nil
}

@ -24,7 +24,10 @@ var (
const PublicKeySizeInBytes = 48
// State is the collection of all committees
type State []Committee
type State struct {
Epoch *big.Int `json:"epoch"`
Shards []Committee `json:"shards"`
}
// BlsPublicKey defines the bls public key
type BlsPublicKey [PublicKeySizeInBytes]byte
@ -70,7 +73,7 @@ type CommitteeLegacy struct {
}
// DecodeWrapper ..
func DecodeWrapper(shardState []byte) (State, error) {
func DecodeWrapper(shardState []byte) (*State, error) {
oldSS := StateLegacy{}
newSS := State{}
var (
@ -79,20 +82,22 @@ func DecodeWrapper(shardState []byte) (State, error) {
)
err1 = rlp.DecodeBytes(shardState, &newSS)
if err1 == nil {
return newSS, nil
return &newSS, nil
}
err2 = rlp.DecodeBytes(shardState, &oldSS)
if err2 == nil {
newSS = make(State, len(oldSS))
newSS := State{}
newSS.Shards = make([]Committee, len(oldSS))
for i := range oldSS {
newSS[i] = Committee{ShardID: oldSS[i].ShardID, Slots: SlotList{}}
newSS.Shards[i] = Committee{ShardID: oldSS[i].ShardID, Slots: SlotList{}}
for _, slot := range oldSS[i].Slots {
newSS[i].Slots = append(newSS[i].Slots, Slot{
newSS.Shards[i].Slots = append(newSS.Shards[i].Slots, Slot{
slot.EcdsaAddress, slot.BlsPublicKey, nil,
})
}
}
return newSS, nil
newSS.Epoch = nil // Make sure for legacy state, the epoch is nil
return &newSS, nil
}
return nil, err2
}
@ -106,12 +111,12 @@ func EncodeWrapper(shardState State, isStaking bool) ([]byte, error) {
if isStaking {
data, err = rlp.EncodeToBytes(shardState)
} else {
shardStateLegacy := make(StateLegacy, len(shardState))
for i := range shardState {
shardStateLegacy := make(StateLegacy, len(shardState.Shards))
for i := range shardState.Shards {
shardStateLegacy[i] = CommitteeLegacy{
ShardID: shardState[i].ShardID, Slots: SlotListLegacy{},
ShardID: shardState.Shards[i].ShardID, Slots: SlotListLegacy{},
}
for _, slot := range shardState[i].Slots {
for _, slot := range shardState.Shards[i].Slots {
shardStateLegacy[i].Slots = append(shardStateLegacy[i].Slots, SlotLegacy{
slot.EcdsaAddress, slot.BlsPublicKey,
})
@ -125,7 +130,7 @@ func EncodeWrapper(shardState State, isStaking bool) ([]byte, error) {
}
// JSON produces a non-pretty printed JSON string of the SuperCommittee
func (ss State) JSON() string {
func (ss *State) JSON() string {
type t struct {
Slot
EcdsaAddress string `json:"ecdsa-address"`
@ -135,14 +140,14 @@ func (ss State) JSON() string {
Count int `json:"member-count"`
NodeList []t `json:"subcommittee"`
}
dump := make([]v, len(ss))
for i := range ss {
c := len(ss[i].Slots)
dump[i].ShardID = ss[i].ShardID
dump := make([]v, len(ss.Shards))
for i := range ss.Shards {
c := len(ss.Shards[i].Slots)
dump[i].ShardID = ss.Shards[i].ShardID
dump[i].NodeList = make([]t, c)
dump[i].Count = c
for j := range ss[i].Slots {
n := ss[i].Slots[j]
for j := range ss.Shards[i].Slots {
n := ss.Shards[i].Slots[j]
dump[i].NodeList[j].BlsPublicKey = n.BlsPublicKey
dump[i].NodeList[j].TotalStake = n.TotalStake
dump[i].NodeList[j].EcdsaAddress = common2.MustAddressToBech32(n.EcdsaAddress)
@ -154,42 +159,25 @@ func (ss State) JSON() string {
// FindCommitteeByID returns the committee configuration for the given shard,
// or nil if the given shard is not found.
func (ss State) FindCommitteeByID(shardID uint32) *Committee {
for committee := range ss {
if ss[committee].ShardID == shardID {
return &ss[committee]
func (ss *State) FindCommitteeByID(shardID uint32) *Committee {
for committee := range ss.Shards {
if ss.Shards[committee].ShardID == shardID {
return &ss.Shards[committee]
}
}
return nil
}
// DeepCopy returns a deep copy of the receiver.
func (ss State) DeepCopy() State {
func (ss *State) DeepCopy() *State {
var r State
for _, c := range ss {
r = append(r, c.DeepCopy())
}
return r
}
// CompareShardState compares two State instances.
func CompareShardState(s1, s2 State) int {
commonLen := len(s1)
if commonLen > len(s2) {
commonLen = len(s2)
if ss.Epoch != nil {
r.Epoch = big.NewInt(0).Set(ss.Epoch)
}
for idx := 0; idx < commonLen; idx++ {
if c := CompareCommittee(&s1[idx], &s2[idx]); c != 0 {
return c
}
for _, c := range ss.Shards {
r.Shards = append(r.Shards, c.DeepCopy())
}
switch {
case len(s1) < len(s2):
return -1
case len(s1) > len(s2):
return +1
}
return 0
return &r
}
// Big ..
@ -312,27 +300,22 @@ func GetHashFromNodeList(nodeList []Slot) []byte {
}
// Hash is the root hash of State
func (ss State) Hash() (h common.Hash) {
func (ss *State) Hash() (h common.Hash) {
// TODO ek – this sorting really doesn't belong here; it should instead
// be made an explicit invariant to be maintained and, if needed, checked.
copy := ss.DeepCopy()
sort.Slice(copy, func(i, j int) bool {
return copy[i].ShardID < copy[j].ShardID
sort.Slice(copy.Shards, func(i, j int) bool {
return copy.Shards[i].ShardID < copy.Shards[j].ShardID
})
d := sha3.NewLegacyKeccak256()
for i := range copy {
hash := GetHashFromNodeList(copy[i].Slots)
for i := range copy.Shards {
hash := GetHashFromNodeList(copy.Shards[i].Slots)
d.Write(hash)
}
d.Sum(h[:0])
return h
}
// CompareNodeIDByBLSKey compares two nodes by their ID; used to sort node list
func CompareNodeIDByBLSKey(n1 Slot, n2 Slot) int {
return bytes.Compare(n1.BlsPublicKey[:], n2.BlsPublicKey[:])
}
// Serialize serialize Slot into bytes
func (n Slot) Serialize() []byte {
return append(n.EcdsaAddress[:], n.BlsPublicKey[:]...)

@ -73,7 +73,7 @@ func TestHash(t *testing.T) {
{common.Address{0x66}, blsPubKey6, nil},
},
}
shardState1 := State{com1, com2}
shardState1 := State{nil, []Committee{com1, com2}}
h1 := shardState1.Hash()
com3 := Committee{
@ -93,7 +93,7 @@ func TestHash(t *testing.T) {
},
}
shardState2 := State{com3, com4}
shardState2 := State{nil, []Committee{com3, com4}}
h2 := shardState2.Hash()
if bytes.Compare(h1[:], h2[:]) != 0 {
@ -120,7 +120,7 @@ func TestCompatibilityOldShardStateIntoNew(t *testing.T) {
}},
}
postStakingState := State{
postStakingState := State{nil, []Committee{
Committee{ShardID: 0, Slots: SlotList{
Slot{junkA, blsPubKey1, nil},
Slot{junkA, blsPubKey2, nil},
@ -134,7 +134,7 @@ func TestCompatibilityOldShardStateIntoNew(t *testing.T) {
Slot{junkA, blsPubKey4, nil},
Slot{junkA, blsPubKey5, &stake2},
}},
}
}}
preStakingStateBytes, _ := rlp.EncodeToBytes(preStakingState)
postStakingStateBytes, _ := rlp.EncodeToBytes(postStakingState)

@ -271,19 +271,6 @@ func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator) error
validator.MaxTotalDelegation = edit.MaxTotalDelegation
}
if edit.SlotKeyToAdd != nil {
found := false
for _, key := range validator.SlotPubKeys {
if key == *edit.SlotKeyToAdd {
found = true
break
}
}
if !found {
validator.SlotPubKeys = append(validator.SlotPubKeys, *edit.SlotKeyToAdd)
}
}
if edit.SlotKeyToRemove != nil {
index := -1
for i, key := range validator.SlotPubKeys {
@ -297,6 +284,19 @@ func UpdateValidatorFromEditMsg(validator *Validator, edit *EditValidator) error
validator.SlotPubKeys = append(validator.SlotPubKeys[:index], validator.SlotPubKeys[index+1:]...)
}
}
if edit.SlotKeyToAdd != nil {
found := false
for _, key := range validator.SlotPubKeys {
if key == *edit.SlotKeyToAdd {
found = true
break
}
}
if !found {
validator.SlotPubKeys = append(validator.SlotPubKeys, *edit.SlotKeyToAdd)
}
}
return nil
}

Loading…
Cancel
Save