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/shard/shard_state.go

221 lines
5.3 KiB

package shard
import (
"bytes"
"encoding/hex"
"sort"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/bls/ffi/go/bls"
"golang.org/x/crypto/sha3"
common2 "github.com/harmony-one/harmony/internal/common"
"github.com/harmony-one/harmony/internal/ctxerror"
)
var (
emptyBlsPubKey = BlsPublicKey{}
)
// EpochShardState is the shard state of an epoch
type EpochShardState struct {
Epoch uint64
ShardState State
}
// State is the collection of all committees
type State []Committee
// 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 committee.ShardID == shardID {
return &committee
}
}
return nil
}
// DeepCopy returns a deep copy of the receiver.
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)
}
for idx := 0; idx < commonLen; idx++ {
if c := CompareCommittee(&s1[idx], &s2[idx]); c != 0 {
return c
}
}
switch {
case len(s1) < len(s2):
return -1
case len(s1) > len(s2):
return +1
}
return 0
}
// BlsPublicKey defines the bls public key
type BlsPublicKey [48]byte
// IsEmpty returns whether the bls public key is empty 0 bytes
func (pk BlsPublicKey) IsEmpty() bool {
return bytes.Compare(pk[:], emptyBlsPubKey[:]) == 0
}
// Hex returns the hex string of bls public key
func (pk BlsPublicKey) Hex() string {
return hex.EncodeToString(pk[:])
}
// FromLibBLSPublicKey replaces the key contents with the given key,
func (pk *BlsPublicKey) FromLibBLSPublicKey(key *bls.PublicKey) error {
bytes := key.Serialize()
if len(bytes) != len(pk) {
return ctxerror.New("BLS public key size mismatch",
"expected", len(pk),
"actual", len(bytes))
}
copy(pk[:], bytes)
return nil
}
// ToLibBLSPublicKey copies the key contents into the given key.
func (pk *BlsPublicKey) ToLibBLSPublicKey(key *bls.PublicKey) error {
return key.Deserialize(pk[:])
}
// CompareBlsPublicKey compares two BlsPublicKey, lexicographically.
func CompareBlsPublicKey(k1, k2 BlsPublicKey) int {
return bytes.Compare(k1[:], k2[:])
}
// NodeID represents node id (BLS address).
type NodeID struct {
EcdsaAddress common.Address `json:"ecdsa_address"`
BlsPublicKey BlsPublicKey `json:"bls_pubkey"`
}
// CompareNodeID compares two node IDs.
func CompareNodeID(id1, id2 *NodeID) int {
if c := bytes.Compare(id1.EcdsaAddress[:], id2.EcdsaAddress[:]); c != 0 {
return c
}
if c := CompareBlsPublicKey(id1.BlsPublicKey, id2.BlsPublicKey); c != 0 {
return c
}
return 0
}
// NodeIDList is a list of NodeIDList.
type NodeIDList []NodeID
// DeepCopy returns a deep copy of the receiver.
func (l NodeIDList) DeepCopy() NodeIDList {
return append(l[:0:0], l...)
}
// CompareNodeIDList compares two node ID lists.
func CompareNodeIDList(l1, l2 NodeIDList) int {
commonLen := len(l1)
if commonLen > len(l2) {
commonLen = len(l2)
}
for idx := 0; idx < commonLen; idx++ {
if c := CompareNodeID(&l1[idx], &l2[idx]); c != 0 {
return c
}
}
switch {
case len(l1) < len(l2):
return -1
case len(l1) > len(l2):
return +1
}
return 0
}
// Committee contains the active nodes in one shard
type Committee struct {
ShardID uint32 `json:"shard_id"`
NodeList NodeIDList `json:"node_list"`
}
// DeepCopy returns a deep copy of the receiver.
func (c Committee) DeepCopy() Committee {
r := Committee{}
r.ShardID = c.ShardID
r.NodeList = c.NodeList.DeepCopy()
return r
}
// CompareCommittee compares two committees and their leader/node list.
func CompareCommittee(c1, c2 *Committee) int {
switch {
case c1.ShardID < c2.ShardID:
return -1
case c1.ShardID > c2.ShardID:
return +1
}
if c := CompareNodeIDList(c1.NodeList, c2.NodeList); c != 0 {
return c
}
return 0
}
// GetHashFromNodeList will sort the list, then use Keccak256 to hash the list
// NOTE: do not modify the underlining content for hash
func GetHashFromNodeList(nodeList []NodeID) []byte {
// in general, nodeList should not be empty
if nodeList == nil || len(nodeList) == 0 {
return []byte{}
}
d := sha3.NewLegacyKeccak256()
for _, nodeID := range nodeList {
d.Write(nodeID.Serialize())
}
return d.Sum(nil)
}
// Hash is the root hash of State
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
})
d := sha3.NewLegacyKeccak256()
for i := range copy {
hash := GetHashFromNodeList(copy[i].NodeList)
d.Write(hash)
}
d.Sum(h[:0])
return h
}
// CompareNodeIDByBLSKey compares two nodes by their ID; used to sort node list
func CompareNodeIDByBLSKey(n1 NodeID, n2 NodeID) int {
return bytes.Compare(n1.BlsPublicKey[:], n2.BlsPublicKey[:])
}
// Serialize serialize NodeID into bytes
func (n NodeID) Serialize() []byte {
return append(n.EcdsaAddress[:], n.BlsPublicKey[:]...)
}
func (n NodeID) String() string {
return "ECDSA: " + common2.MustAddressToBech32(n.EcdsaAddress) + ", BLS: " + hex.EncodeToString(n.BlsPublicKey[:])
}