Merge pull request #529 from LeoHChen/add_node_config_module

Add node config module
pull/531/head
Leo Chen 6 years ago committed by GitHub
commit 79b788d88d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      api/service/config.go
  2. 11
      api/service/manager_test.go
  3. 3
      cmd/client/txgen/main.go
  4. 19
      cmd/harmony.go
  5. 165
      internal/configs/node/config.go
  6. 75
      internal/configs/node/config_test.go
  7. 50
      node/node.go
  8. 18
      node/node_handler.go
  9. 15
      node/service_setup.go
  10. 13
      p2p/group.go

@ -1,6 +1,9 @@
package service
import (
"strconv"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/p2p"
)
@ -9,9 +12,36 @@ import (
// This is to pass node configuration to services and prvent
// cyclic imports
type NodeConfig struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
Beacon p2p.GroupID // the beacon group ID
Group p2p.GroupID // the group ID of the shard
Client p2p.GroupID // the client group ID of the shard
IsClient bool // whether this node is a client node, such as wallet/txgen
IsBeacon bool // whether this node is a beacon node or not
IsLeader bool // whether this node is a leader or not
ShardID uint32 // shardID of this node
Actions map[p2p.GroupID]p2p.ActionType // actions on the groups
}
// GroupIDShards is a map of Group ID
// key is the shard ID
// value is the corresponding group ID
var (
GroupIDShards map[p2p.ShardIDType]p2p.GroupID
GroupIDShardClients map[p2p.ShardIDType]p2p.GroupID
)
func init() {
GroupIDShards = make(map[p2p.ShardIDType]p2p.GroupID)
GroupIDShardClients = make(map[p2p.ShardIDType]p2p.GroupID)
// init beacon chain group IDs
GroupIDShards["0"] = p2p.GroupIDBeacon
GroupIDShardClients["0"] = p2p.GroupIDBeaconClient
for i := 1; i < nodeconfig.MaxShards; i++ {
sid := p2p.ShardIDType(strconv.Itoa(i))
GroupIDShards[sid] = p2p.NewGroupIDShard(sid)
GroupIDShardClients[sid] = p2p.NewGroupIDShardClient(sid)
}
}

@ -6,6 +6,8 @@ import (
"time"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/p2p"
)
type SupportSyncingTest struct {
@ -95,3 +97,12 @@ func TestStopServices(t *testing.T) {
t.Error("Service did not stop")
}
}
func TestInit(t *testing.T) {
if GroupIDShards[p2p.ShardIDType("0")] != p2p.GroupIDBeacon {
t.Errorf("GroupIDShards[0]: %v != GroupIDBeacon: %v", GroupIDShards[p2p.ShardIDType("0")], p2p.GroupIDBeacon)
}
if len(GroupIDShards) != nodeconfig.MaxShards {
t.Errorf("len(GroupIDShards): %v != TotalShards: %v", len(GroupIDShards), nodeconfig.MaxShards)
}
}

@ -15,6 +15,7 @@ import (
"github.com/harmony-one/harmony/cmd/client/txgen/txgen"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/core/types"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/node"
"github.com/harmony-one/harmony/p2p"
@ -148,7 +149,7 @@ func main() {
}
clientNode.Client.UpdateBlocks = updateBlocksFunc
clientNode.Role = node.ClientNode
clientNode.NodeConfig.SetRole(nodeconfig.ClientNode)
clientNode.ServiceManagerSetup()
clientNode.RunServices()

@ -13,6 +13,7 @@ import (
"github.com/ethereum/go-ethereum/log"
"github.com/harmony-one/harmony/consensus"
"github.com/harmony-one/harmony/drand"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/profiler"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/node"
@ -200,7 +201,7 @@ func main() {
// Current node.
currentNode := node.New(host, consensus, ldb)
currentNode.Consensus.OfflinePeers = currentNode.OfflinePeers
currentNode.Role = node.NewNode
currentNode.NodeConfig.SetRole(nodeconfig.NewNode)
currentNode.AccountKey = stakingPriKey
// TODO: refactor the creation of blockchain out of node.New()
@ -208,11 +209,11 @@ func main() {
if *isBeacon {
if role == "leader" {
currentNode.Role = node.BeaconLeader
currentNode.NodeConfig.SetRole(nodeconfig.BeaconLeader)
} else {
currentNode.Role = node.BeaconValidator
currentNode.NodeConfig.SetRole(nodeconfig.BeaconValidator)
}
currentNode.MyShardGroupID = p2p.GroupIDBeacon
currentNode.NodeConfig.SetShardGroupID(p2p.GroupIDBeacon)
} else {
var beacondb ethdb.Database
if *dbSupported {
@ -221,13 +222,13 @@ func main() {
currentNode.AddBeaconChainDatabase(beacondb)
if *isNewNode {
currentNode.Role = node.NewNode
currentNode.NodeConfig.SetRole(nodeconfig.NewNode)
} else if role == "leader" {
currentNode.Role = node.ShardLeader
currentNode.NodeConfig.SetRole(nodeconfig.ShardLeader)
} else {
currentNode.Role = node.ShardValidator
currentNode.NodeConfig.SetRole(nodeconfig.ShardValidator)
}
currentNode.MyShardGroupID = p2p.GroupIDUnknown
currentNode.NodeConfig.SetShardGroupID(p2p.GroupIDUnknown)
}
// Add randomness protocol
@ -252,7 +253,7 @@ func main() {
go currentNode.SendPongMessage()
}
log.Info("New Harmony Node ====", "Role", currentNode.Role, "multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, host.GetID().Pretty()))
log.Info("New Harmony Node ====", "Role", currentNode.NodeConfig.Role(), "multiaddress", fmt.Sprintf("/ip4/%s/tcp/%s/p2p/%s", *ip, *port, host.GetID().Pretty()))
go currentNode.SupportSyncing()
currentNode.ServiceManagerSetup()
currentNode.RunServices()

@ -0,0 +1,165 @@
// Package nodeconfig includes all the configuration variables for a node.
// It is a global configuration for node and other services.
// It will be included in node module, and other modules.
package nodeconfig
import (
"fmt"
"sync"
"github.com/harmony-one/harmony/p2p"
)
// Role defines a role of a node.
type Role byte
// All constants for different node roles.
const (
Unknown Role = iota
ShardLeader
ShardValidator
BeaconLeader
BeaconValidator
NewNode
ClientNode
)
func (role Role) String() string {
switch role {
case Unknown:
return "Unknown"
case ShardLeader:
return "ShardLeader"
case ShardValidator:
return "ShardValidator"
case BeaconLeader:
return "BeaconLeader"
case BeaconValidator:
return "BeaconValidator"
case NewNode:
return "NewNode"
case ClientNode:
return "ClientNode"
}
return "Unknown"
}
// Global is the index of the global node configuration
const (
Global = 0
MaxShards = 32 // maximum number of shards. It is also the maxium number of configs.
)
// ConfigType is the structure of all node related configuration variables
type ConfigType struct {
// The three groupID design, please refer to https://github.com/harmony-one/harmony/blob/master/node/node.md#libp2p-integration
beacon p2p.GroupID // the beacon group ID
group p2p.GroupID // the group ID of the shard
client p2p.GroupID // the client group ID of the shard
isClient bool // whether this node is a client node, such as wallet/txgen
isBeacon bool // whether this node is a beacon node or not
isLeader bool // whether this node is a leader or not
shardID uint32 // shardID of this node
role Role // Role of the node
}
// configs is a list of node configuration.
// It has at least one configuration.
// The first one is the default, global node configuration
var configs []ConfigType
var onceForConfigs sync.Once
// GetConfigs return the indexed ConfigType variable
func GetConfigs(index int) *ConfigType {
onceForConfigs.Do(func() {
configs = make([]ConfigType, MaxShards)
})
if index > cap(configs) {
return nil
}
return &configs[index]
}
func (conf *ConfigType) String() string {
return fmt.Sprintf("%s/%s/%s:%v,%v,%v:%v", conf.beacon, conf.group, conf.client, conf.isClient, conf.isBeacon, conf.isLeader, conf.shardID)
}
// SetBeaconGroupID set the groupID for beacon group
func (conf *ConfigType) SetBeaconGroupID(g p2p.GroupID) {
conf.beacon = g
}
// SetShardGroupID set the groupID for shard group
func (conf *ConfigType) SetShardGroupID(g p2p.GroupID) {
conf.group = g
}
// SetClientGroupID set the groupID for client group
func (conf *ConfigType) SetClientGroupID(g p2p.GroupID) {
conf.client = g
}
// SetIsClient set the isClient configuration
func (conf *ConfigType) SetIsClient(b bool) {
conf.isClient = b
}
// SetIsBeacon set the isBeacon configuration
func (conf *ConfigType) SetIsBeacon(b bool) {
conf.isBeacon = b
}
// SetIsLeader set the isLeader configuration
func (conf *ConfigType) SetIsLeader(b bool) {
conf.isLeader = b
}
// SetShardID set the shardID
func (conf *ConfigType) SetShardID(s uint32) {
conf.shardID = s
}
// SetRole set the role
func (conf *ConfigType) SetRole(r Role) {
conf.role = r
}
// GetBeaconGroupID returns the groupID for beacon group
func (conf *ConfigType) GetBeaconGroupID() p2p.GroupID {
return conf.beacon
}
// GetShardGroupID returns the groupID for shard group
func (conf *ConfigType) GetShardGroupID() p2p.GroupID {
return conf.group
}
// GetClientGroupID returns the groupID for client group
func (conf *ConfigType) GetClientGroupID() p2p.GroupID {
return conf.client
}
// IsClient returns the isClient configuration
func (conf *ConfigType) IsClient() bool {
return conf.isClient
}
// IsBeacon returns the isBeacon configuration
func (conf *ConfigType) IsBeacon() bool {
return conf.isBeacon
}
// IsLeader returns the isLeader configuration
func (conf *ConfigType) IsLeader() bool {
return conf.isLeader
}
// ShardID returns the shardID
func (conf *ConfigType) ShardID() uint32 {
return conf.shardID
}
// Role returns the role
func (conf *ConfigType) Role() Role {
return conf.role
}

@ -0,0 +1,75 @@
package nodeconfig
import (
"testing"
"github.com/harmony-one/harmony/p2p"
)
func TestNodeConfigSingleton(t *testing.T) {
// init 3 configs
_ = GetConfigs(2)
// get the singleton variable
c := GetConfigs(Global)
c.SetIsLeader(true)
if !c.IsLeader() {
t.Errorf("IsLeader = %v, expected = %v", c.IsLeader(), true)
}
c.SetBeaconGroupID(p2p.GroupIDBeacon)
d := GetConfigs(Global)
if !d.IsLeader() {
t.Errorf("IsLeader = %v, expected = %v", d.IsLeader(), true)
}
g := d.GetBeaconGroupID()
if g != p2p.GroupIDBeacon {
t.Errorf("GetBeaconGroupID = %v, expected = %v", g, p2p.GroupIDBeacon)
}
}
func TestNodeConfigMultiple(t *testing.T) {
// init 3 configs
c := GetConfigs(2)
d := GetConfigs(1)
e := GetConfigs(0)
f := GetConfigs(42)
if f != nil {
t.Errorf("expecting nil, got: %v", f)
}
c.SetIsBeacon(true)
if c.IsBeacon() != true {
t.Errorf("expecting true, got: %v", c.IsBeacon())
}
d.SetShardGroupID("abcd")
if d.GetShardGroupID() != "abcd" {
t.Errorf("expecting abcd, got: %v", d.GetShardGroupID())
}
e.SetClientGroupID("client")
if e.GetClientGroupID() != "client" {
t.Errorf("expecting client, got: %v", d.GetClientGroupID())
}
e.SetIsClient(false)
if e.IsClient() != false {
t.Errorf("expecting false, got: %v", e.IsClient())
}
c.SetRole(NewNode)
if c.Role() != NewNode {
t.Errorf("expecting NewNode, got: %s", c.Role())
}
if c.Role().String() != "NewNode" {
t.Errorf("expecting NewNode, got: %s", c.Role().String())
}
}

@ -25,6 +25,7 @@ import (
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/pki"
"github.com/harmony-one/harmony/drand"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/node/worker"
"github.com/harmony-one/harmony/p2p"
@ -44,40 +45,6 @@ const (
NodeLeader // Node is the leader of some shard.
)
// Role defines a role of a node.
type Role byte
// All constants for different node roles.
const (
Unknown Role = iota
ShardLeader
ShardValidator
BeaconLeader
BeaconValidator
NewNode
ClientNode
)
func (role Role) String() string {
switch role {
case Unknown:
return "Unknown"
case ShardLeader:
return "ShardLeader"
case ShardValidator:
return "ShardValidator"
case BeaconLeader:
return "BeaconLeader"
case BeaconValidator:
return "BeaconValidator"
case NewNode:
return "NewNode"
case ClientNode:
return "ClientNode"
}
return "Unknown"
}
func (state State) String() string {
switch state {
case NodeInit:
@ -164,9 +131,6 @@ type Node struct {
// Signal channel for lost validators
OfflinePeers chan p2p.Peer
// Node Role.
Role Role
// Service manager.
serviceManager *service.Manager
@ -197,11 +161,8 @@ type Node struct {
// Channel to notify consensus service to really start consensus
startConsensus chan struct{}
// My GroupID
MyShardGroupID p2p.GroupID
// My ShardClient GroupID
MyClientGroupID p2p.GroupID
// node configuration, including group ID, shard ID, etc
NodeConfig *nodeconfig.ConfigType
// map of service type to its message channel.
serviceMessageChan map[service.Type]chan *msg_pb.Message
@ -308,6 +269,9 @@ func New(host p2p.Host, consensusObj *consensus.Consensus, db ethdb.Database) *N
node.startConsensus = make(chan struct{})
// init the global and the only node config
node.NodeConfig = nodeconfig.GetConfigs(nodeconfig.Global)
return &node
}
@ -480,7 +444,7 @@ func (node *Node) initBeaconNodeConfiguration() (service.NodeConfig, chan p2p.Pe
if err != nil {
utils.GetLogInstance().Error("create client receiver error", "msg", err)
}
node.MyClientGroupID = p2p.GroupIDBeaconClient
node.NodeConfig.SetClientGroupID(p2p.GroupIDBeaconClient)
return nodeConfig, chanPeer
}

@ -19,6 +19,7 @@ import (
"github.com/harmony-one/harmony/api/service"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/pki"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
"github.com/harmony-one/harmony/p2p/host"
@ -131,7 +132,7 @@ func (node *Node) messageHandler(content []byte, sender string) {
case proto.Staking:
msgPayload, _ := proto.GetStakingMessagePayload(content)
// Only beacon leader processes staking txn
if node.Role != BeaconLeader {
if node.NodeConfig.Role() != nodeconfig.BeaconLeader {
return
}
node.processStakingMessage(msgPayload)
@ -153,7 +154,8 @@ func (node *Node) messageHandler(content []byte, sender string) {
utils.GetLogInstance().Error("block sync", "error", err)
} else {
// for non-beaconchain node, subscribe to beacon block broadcast
if proto_node.BlockMessageType(msgPayload[0]) == proto_node.Sync && node.Role != BeaconValidator && node.Role != BeaconLeader && node.Role != ClientNode {
role := node.NodeConfig.Role()
if proto_node.BlockMessageType(msgPayload[0]) == proto_node.Sync && role != nodeconfig.BeaconValidator && role != nodeconfig.BeaconLeader && role != nodeconfig.ClientNode {
for _, block := range blocks {
node.BeaconBlockChannel <- block
}
@ -260,7 +262,7 @@ func (node *Node) transactionMessageHandler(msgPayload []byte) {
func (node *Node) BroadcastNewBlock(newBlock *types.Block) {
if node.ClientPeer != nil {
utils.GetLogInstance().Debug("Sending new block to client", "client", node.ClientPeer)
node.host.SendMessageToGroups([]p2p.GroupID{node.MyClientGroupID}, host.ConstructP2pMessage(byte(0), proto_node.ConstructBlocksSyncMessage([]*types.Block{newBlock})))
node.host.SendMessageToGroups([]p2p.GroupID{node.NodeConfig.GetClientGroupID()}, host.ConstructP2pMessage(byte(0), proto_node.ConstructBlocksSyncMessage([]*types.Block{newBlock})))
}
}
@ -287,7 +289,7 @@ func (node *Node) VerifyNewBlock(newBlock *types.Block) bool {
// 2. [leader] send new block to the client
func (node *Node) PostConsensusProcessing(newBlock *types.Block) {
utils.GetLogInstance().Info("PostConsensusProcessing")
if node.Role == BeaconLeader {
if node.NodeConfig.Role() == nodeconfig.BeaconLeader {
utils.GetLogInstance().Info("Updating staking list")
node.UpdateStakingList(newBlock)
node.printStakingList()
@ -394,12 +396,12 @@ func (node *Node) SendPongMessage() {
if !sentMessage && numPubKeysNow >= node.Consensus.MinPeers {
pong := proto_discovery.NewPongMessage(peers, node.Consensus.PublicKeys, node.Consensus.GetLeaderPubKey())
buffer := pong.ConstructPongMessage()
err := node.host.SendMessageToGroups([]p2p.GroupID{node.MyShardGroupID}, host.ConstructP2pMessage(byte(0), buffer))
err := node.host.SendMessageToGroups([]p2p.GroupID{node.NodeConfig.GetShardGroupID()}, host.ConstructP2pMessage(byte(0), buffer))
if err != nil {
utils.GetLogInstance().Error("[PONG] failed to send pong message", "group", node.MyShardGroupID)
utils.GetLogInstance().Error("[PONG] failed to send pong message", "group", node.NodeConfig.GetShardGroupID())
continue
} else {
utils.GetLogInstance().Info("[PONG] sent pong message to", "group", node.MyShardGroupID)
utils.GetLogInstance().Info("[PONG] sent pong message to", "group", node.NodeConfig.GetShardGroupID())
}
sentMessage = true
// stop sending ping message
@ -484,7 +486,7 @@ func (node *Node) pongMessageHandler(msgPayload []byte) int {
// Stop discovery service after received pong message
data := make(map[string]interface{})
data["peer"] = p2p.GroupAction{Name: node.MyShardGroupID, Action: p2p.ActionPause}
data["peer"] = p2p.GroupAction{Name: node.NodeConfig.GetShardGroupID(), Action: p2p.ActionPause}
node.serviceManager.TakeAction(&service.Action{Action: service.Notify, ServiceType: service.PeerDiscovery, Params: data})
return node.Consensus.UpdatePublicKeys(publicKeys) + node.DRand.UpdatePublicKeys(publicKeys)

@ -11,6 +11,7 @@ import (
"github.com/harmony-one/harmony/api/service/networkinfo"
"github.com/harmony-one/harmony/api/service/randomness"
"github.com/harmony-one/harmony/api/service/staking"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p"
)
@ -96,18 +97,18 @@ func (node *Node) setupForClientNode() {
func (node *Node) ServiceManagerSetup() {
node.serviceManager = &service.Manager{}
node.serviceMessageChan = make(map[service.Type]chan *msg_pb.Message)
switch node.Role {
case ShardLeader:
switch node.NodeConfig.Role() {
case nodeconfig.ShardLeader:
node.setupForShardLeader()
case ShardValidator:
case nodeconfig.ShardValidator:
node.setupForShardValidator()
case BeaconLeader:
case nodeconfig.BeaconLeader:
node.setupForBeaconLeader()
case BeaconValidator:
case nodeconfig.BeaconValidator:
node.setupForBeaconValidator()
case NewNode:
case nodeconfig.NewNode:
node.setupForNewNode()
case ClientNode:
case nodeconfig.ClientNode:
node.setupForClientNode()
}
node.serviceManager.SetupServiceMessageChan(node.serviceMessageChan)

@ -30,6 +30,19 @@ const (
GroupIDUnknown GroupID = "B1acKh0lE"
)
// ShardIDType defines the data type of a shard ID
type ShardIDType string
// NewGroupIDShard returns a new groupID for a shard
func NewGroupIDShard(sid ShardIDType) GroupID {
return GroupID(fmt.Sprintf("harmony/0.0.1/shard/%s", sid))
}
// NewGroupIDShardClient returns a new groupID for a shard's client
func NewGroupIDShardClient(sid ShardIDType) GroupID {
return GroupID(fmt.Sprintf("harmony/0.0.1/shard/%s/client", sid))
}
// ActionType lists action on group
type ActionType uint

Loading…
Cancel
Save