Skip to content

Commit

Permalink
Rename Stake to Weight (onflow#2090)
Browse files Browse the repository at this point in the history
* rename: stake->weight (comments/variables 1)

* auto-rename Identity.Stake struct field

* rename missed variable

* rename WithStake

* rename unittest.WithStake

* rename mockStakedAtBlockID

* rename ensureStakedNodeWithRole

* update flow.Identity

* rename filter.HasStake

* rename bootstrap models

* rename IsNodeStaked helpers

* rename stake references in hotstuff

* collection engines

* en engines

* vn engine

* validation rename

* update bootstrap cli

* update outstanding comments

* outstanding string variables

* rename in integration tests

* don't use Identity when staking in fvn bootstrap

* remove unecessary stealthIdentity

* backward-compatible decoding

Identity, NodeConfig, NodeInfoPub

* misc cleanups

* typo

* Apply suggestions from code review

Co-authored-by: Alexander Hentschel <[email protected]>

* additional instances of stake term

Co-authored-by: Alexander Hentschel <[email protected]>
  • Loading branch information
jordanschalm and Alexander Hentschel authored Mar 5, 2022
1 parent e7fec51 commit bd91074
Show file tree
Hide file tree
Showing 101 changed files with 1,123 additions and 903 deletions.
8 changes: 4 additions & 4 deletions cmd/bootstrap/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The bootstrapping will generate the following information:
- node role
- public staking key
- public networking key
- stake
- weight

#### Root Block for main consensus
* Root Block
Expand Down Expand Up @@ -92,8 +92,8 @@ Each input is a config file specified as a command line parameter:
* parameter with state commitment for the initial execution state (`root-commit`)
* `json` containing configuration for all Dapper-Controlled nodes (see `./example_files/node-config.json`)
* folder containing the `<NodeID>.node-info.pub.json` files for _all_ partner nodes (see `.example_files/partner-node-infos`)
* `json` containing the stake value for all partner nodes (see `./example_files/partner-stakes.json`).
Format: ```<NodeID>: <stake value>```
* `json` containing the weight value for all partner nodes (see `./example_files/partner-weights.json`).
Format: ```<NodeID>: <weight value>```

#### Example
```bash
Expand All @@ -105,7 +105,7 @@ go run -tags relic ./cmd/bootstrap finalize \
--root-commit 4b8d01975cf0cd23e046b1fae36518e542f92a6e35bedd627c43da30f4ae761a \
--config ./cmd/bootstrap/example_files/node-config.json \
--partner-dir ./cmd/bootstrap/example_files/partner-node-infos \
--partner-stakes ./cmd/bootstrap/example_files/partner-stakes.json \
--partner-weights ./cmd/bootstrap/example_files/partner-weights.json \
--epoch-counter 1 \
-o ./bootstrap/root-infos
```
Expand Down
12 changes: 6 additions & 6 deletions cmd/bootstrap/cmd/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ import (
// ensureUniformNodeWeightsPerRole verifies that the following condition is satisfied for each role R:
// * all node with role R must have the same weight
func ensureUniformNodeWeightsPerRole(allNodes flow.IdentityList) {
// ensure all nodes of the same role have equal stake/weight
// ensure all nodes of the same role have equal weight
for _, role := range flow.Roles() {
withRole := allNodes.Filter(filter.HasRole(role))
expectedStake := withRole[0].Stake
expectedWeight := withRole[0].Weight
for _, node := range withRole {
if node.Stake != expectedStake {
if node.Weight != expectedWeight {
log.Fatal().Msgf(
"will not bootstrap configuration with non-equal stakes\n"+
"found nodes with role %s and stake1=%d, stake2=%d",
role, expectedStake, node.Stake)
"will not bootstrap configuration with non-equal weights\n"+
"found nodes with role %s and weight1=%d, weight2=%d",
role, expectedWeight, node.Weight)
}
}
}
Expand Down
167 changes: 93 additions & 74 deletions cmd/bootstrap/cmd/final_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var (
flagStakingNodesPath string
)

// finallistCmd represents the final list command
// finalListCmd represents the final list command
var finalListCmd = &cobra.Command{
Use: "finallist",
Short: "generates a final list of nodes to be used for next network",
Expand Down Expand Up @@ -45,92 +45,105 @@ func addFinalListFlags() {
func finalList(cmd *cobra.Command, args []string) {
// read public partner node infos
log.Info().Msgf("reading partner public node information: %s", flagPartnerNodeInfoDir)
partnerNodes := assemblePartnerNodesWithoutStake()
partnerNodes := assemblePartnerNodesWithoutWeight()

// read internal private node infos
log.Info().Msgf("reading internal/flow private node information: %s", flagInternalNodePrivInfoDir)
flowNodes := assembleInternalNodesWithoutStake()
internalNodes := assembleInternalNodesWithoutWeight()

log.Info().Msg("checking constraints on consensus/cluster nodes")
checkConstraints(partnerNodes, flowNodes)
checkConstraints(partnerNodes, internalNodes)

// nodes which are registered on-chain
log.Info().Msgf("reading staking contract node information: %s", flagStakingNodesPath)
stakingNodes := readStakingContractDetails()
registeredNodes := readStakingContractDetails()

// merge internal and partner node infos
mixedNodeInfos := mergeNodeInfos(flowNodes, partnerNodes)
// merge internal and partner node infos (from local files)
localNodes := mergeNodeInfos(internalNodes, partnerNodes)

// reconcile nodes from staking contract nodes
validateNodes(mixedNodeInfos, stakingNodes)
validateNodes(localNodes, registeredNodes)

// write node-config.json with the new list of nodes to be used for the `finalize` command
writeJSON(model.PathFinallist, model.ToPublicNodeInfoList(mixedNodeInfos))
writeJSON(model.PathFinallist, model.ToPublicNodeInfoList(localNodes))
}

func validateNodes(nodes []model.NodeInfo, stakingNodes []model.NodeInfo) {
func validateNodes(localNodes []model.NodeInfo, registeredNodes []model.NodeInfo) {
// check node count
if len(nodes) != len(stakingNodes) {
log.Error().Int("nodes", len(nodes)).Int("staked nodes", len(stakingNodes)).
Msg("staked node count does not match flow and parnter node count")
if len(localNodes) != len(registeredNodes) {
log.Error().
Int("local", len(localNodes)).
Int("onchain", len(registeredNodes)).
Msg("onchain node count does not match local internal+partner node count")
}

// check staked and collected nodes and make sure node ID are not missing
validateNodeIDs(nodes, stakingNodes)
// check registered and local nodes to make sure node ID are not missing
validateNodeIDs(localNodes, registeredNodes)

// print mis matching nodes
checkMisMatchingNodes(nodes, stakingNodes)
// print mismatching nodes
checkMismatchingNodes(localNodes, registeredNodes)

// create map
nodesByID := make(map[flow.Identifier]model.NodeInfo)
for _, node := range nodes {
nodesByID[node.NodeID] = node
localNodeMap := make(map[flow.Identifier]model.NodeInfo)
for _, node := range localNodes {
localNodeMap[node.NodeID] = node
}

// check node type mismatch
for _, stakedNode := range stakingNodes {
for _, registeredNode := range registeredNodes {

// win have matching node as we have a check before
matchingNode := nodesByID[stakedNode.NodeID]
matchingNode := localNodeMap[registeredNode.NodeID]

// check node type and error if mismatch
if matchingNode.Role != stakedNode.Role {
log.Error().Str("staked node", stakedNode.NodeID.String()).
Str("staked node-type", stakedNode.Role.String()).
Str("node", matchingNode.NodeID.String()).
Str("node-type", matchingNode.Role.String()).
Msg("node type does not match")
if matchingNode.Role != registeredNode.Role {
log.Error().
Str("registered node id", registeredNode.NodeID.String()).
Str("registered node role", registeredNode.Role.String()).
Str("local node", matchingNode.NodeID.String()).
Str("local node role", matchingNode.Role.String()).
Msg("node role does not match")
}

// No need to error adderss, and public keys as they may be different
// we only keep node-id constant through out sporks
if matchingNode.Address != registeredNode.Address {
log.Error().
Str("registered node id", registeredNode.NodeID.String()).
Str("registered node address", registeredNode.Address).
Str("local node", matchingNode.NodeID.String()).
Str("local node address", matchingNode.Address).
Msg("node address does not match")
}

// check address match
if matchingNode.Address != stakedNode.Address {
log.Warn().Str("staked node", stakedNode.NodeID.String()).
Str("node", matchingNode.NodeID.String()).
if matchingNode.Address != registeredNode.Address {
log.Warn().
Str("registered node", registeredNode.NodeID.String()).
Str("node id", matchingNode.NodeID.String()).
Msg("address do not match")
}

// flow nodes contain private key info
// flow localNodes contain private key info
if matchingNode.NetworkPubKey().String() != "" {
// check networking pubkey match
matchNodeKey := matchingNode.NetworkPubKey().String()
stakedNodeKey := stakedNode.NetworkPubKey().String()
registeredNodeKey := registeredNode.NetworkPubKey().String()

if matchNodeKey != stakedNodeKey {
log.Warn().Str("staked network key", stakedNodeKey).
if matchNodeKey != registeredNodeKey {
log.Error().
Str("registered network key", registeredNodeKey).
Str("network key", matchNodeKey).
Msg("networking keys do not match")
}
}

// flow nodes contain priv atekey info
// flow localNodes contain privatekey info
if matchingNode.StakingPubKey().String() != "" {
matchNodeKey := matchingNode.StakingPubKey().String()
stakedNodeKey := stakedNode.StakingPubKey().String()
registeredNodeKey := registeredNode.StakingPubKey().String()

if matchNodeKey != stakedNodeKey {
log.Warn().Str("staked staking key", stakedNodeKey).
if matchNodeKey != registeredNodeKey {
log.Error().
Str("registered staking key", registeredNodeKey).
Str("staking key", matchNodeKey).
Msg("staking keys do not match")
}
Expand All @@ -140,31 +153,31 @@ func validateNodes(nodes []model.NodeInfo, stakingNodes []model.NodeInfo) {

// validateNodeIDs will go through both sets of nodes and ensure that no node-id
// are missing. It will log all missing node ID's and throw an error.
func validateNodeIDs(collectedNodes []model.NodeInfo, stakedNodes []model.NodeInfo) {
func validateNodeIDs(localNodes []model.NodeInfo, registeredNodes []model.NodeInfo) {

// go through staking nodes
// go through registered nodes
invalidStakingNodes := make([]model.NodeInfo, 0)
for _, node := range stakedNodes {
for _, node := range registeredNodes {
if node.NodeID.String() == "" {

// we warn here but exit later
invalidStakingNodes = append(invalidStakingNodes, node)
log.Warn().
Str("node-address", node.Address).
Msg("missing node-id from staked nodes")
Msg("missing node-id from registered nodes")
}
}

// go through staking nodes
// go through local nodes
invalidNodes := make([]model.NodeInfo, 0)
for _, node := range collectedNodes {
for _, node := range localNodes {
if node.NodeID.String() == "" {

// we warn here but exit later
invalidNodes = append(invalidNodes, node)
log.Warn().
Str("node-address", node.Address).
Msg("missing node-id from collected nodes")
Msg("missing node-id from local nodes")
}
}

Expand All @@ -173,43 +186,49 @@ func validateNodeIDs(collectedNodes []model.NodeInfo, stakedNodes []model.NodeIn
}
}

func checkMisMatchingNodes(collectedNodes []model.NodeInfo, stakedNodes []model.NodeInfo) {
func checkMismatchingNodes(localNodes []model.NodeInfo, registeredNodes []model.NodeInfo) {

collectedNodesByID := make(map[flow.Identifier]model.NodeInfo)
for _, node := range collectedNodes {
collectedNodesByID[node.NodeID] = node
localNodesByID := make(map[flow.Identifier]model.NodeInfo)
for _, node := range localNodes {
localNodesByID[node.NodeID] = node
}

stakedNodesByID := make(map[flow.Identifier]model.NodeInfo)
for _, node := range stakedNodes {
stakedNodesByID[node.NodeID] = node
registeredNodesByID := make(map[flow.Identifier]model.NodeInfo)
for _, node := range registeredNodes {
registeredNodesByID[node.NodeID] = node
}

// try match collected nodes to staked nodes
invalidCollectedNodes := make([]model.NodeInfo, 0)
for _, node := range collectedNodes {
if _, ok := stakedNodesByID[node.NodeID]; !ok {
log.Warn().Str("collected-node-id", node.NodeID.String()).Str("role", node.Role.String()).Str("address", node.Address).
Msg("matching staked node not found for collected node")
invalidCollectedNodes = append(invalidCollectedNodes, node)
// try match local nodes to registered nodes
invalidLocalNodes := make([]model.NodeInfo, 0)
for _, node := range localNodes {
if _, ok := registeredNodesByID[node.NodeID]; !ok {
log.Warn().
Str("local-node-id", node.NodeID.String()).
Str("role", node.Role.String()).
Str("address", node.Address).
Msg("matching registered node not found for local node")
invalidLocalNodes = append(invalidLocalNodes, node)
}
}

invalidStakedNodes := make([]model.NodeInfo, 0)
for _, node := range stakedNodes {
if _, ok := collectedNodesByID[node.NodeID]; !ok {
log.Warn().Str("staked-node-id", node.NodeID.String()).Str("role", node.Role.String()).Str("address", node.Address).
Msg("matching collected node not found for staked node")
invalidStakedNodes = append(invalidStakedNodes, node)
invalidRegisteredNodes := make([]model.NodeInfo, 0)
for _, node := range registeredNodes {
if _, ok := localNodesByID[node.NodeID]; !ok {
log.Warn().
Str("registered-node-id", node.NodeID.String()).
Str("role", node.Role.String()).
Str("address", node.Address).
Msg("matching local node not found for local node")
invalidRegisteredNodes = append(invalidRegisteredNodes, node)
}
}

if len(invalidCollectedNodes) != 0 || len(invalidStakedNodes) != 0 {
if len(invalidLocalNodes) != 0 || len(invalidRegisteredNodes) != 0 {
log.Fatal().Msg("found missing mismatching nodes")
}
}

func assembleInternalNodesWithoutStake() []model.NodeInfo {
func assembleInternalNodesWithoutWeight() []model.NodeInfo {
privInternals := readInternalNodes()
log.Info().Msgf("read %v internal private node-info files", len(privInternals))

Expand All @@ -224,7 +243,7 @@ func assembleInternalNodesWithoutStake() []model.NodeInfo {
nodeID,
internal.Role,
internal.Address,
1000,
flow.DefaultInitialWeight,
internal.NetworkPrivKey,
internal.StakingPrivKey,
)
Expand All @@ -235,7 +254,7 @@ func assembleInternalNodesWithoutStake() []model.NodeInfo {
return nodes
}

func assemblePartnerNodesWithoutStake() []model.NodeInfo {
func assemblePartnerNodesWithoutWeight() []model.NodeInfo {
partners := readPartnerNodes()
log.Info().Msgf("read %v partner node configuration files", len(partners))
return createPublicNodeInfo(partners)
Expand All @@ -257,12 +276,12 @@ func createPublicNodeInfo(nodes []model.NodeInfoPub) []model.NodeInfo {
networkPubKey := validateNetworkPubKey(n.NetworkPubKey)
stakingPubKey := validateStakingPubKey(n.StakingPubKey)

// stake set to 1000 to give equal weight to each node
// all nodes should have equal weight
node := model.NewPublicNodeInfo(
nodeID,
n.Role,
n.Address,
1000,
flow.DefaultInitialWeight,
networkPubKey,
stakingPubKey,
)
Expand Down
Loading

0 comments on commit bd91074

Please sign in to comment.