github.com/koko1123/flow-go-1@v0.29.6/model/bootstrap/node_info.go (about) 1 // Package bootstrap defines canonical models and encoding for bootstrapping. 2 package bootstrap 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strings" 9 10 sdk "github.com/onflow/flow-go-sdk" 11 sdkcrypto "github.com/onflow/flow-go-sdk/crypto" 12 13 "github.com/onflow/flow-go/crypto" 14 "github.com/koko1123/flow-go-1/model/encodable" 15 "github.com/koko1123/flow-go-1/model/flow" 16 ) 17 18 // NodeInfoType enumerates the two different options for 19 type NodeInfoType int 20 21 const ( 22 NodeInfoTypeInvalid NodeInfoType = iota 23 NodeInfoTypePublic 24 NodeInfoTypePrivate 25 ) 26 27 const ( 28 DefaultMachineAccountSignAlgo = sdkcrypto.ECDSA_P256 29 DefaultMachineAccountHashAlgo = sdkcrypto.SHA3_256 30 DefaultMachineAccountKeyIndex uint = 0 31 ) 32 33 // ErrMissingPrivateInfo is returned when a method is called on NodeInfo 34 // that is only valid on instances containing private info. 35 var ErrMissingPrivateInfo = fmt.Errorf("can not access private information for a public node type") 36 37 // NodeMachineAccountKey contains the private configration need to construct a 38 // NodeMachineAccountInfo object. This is used as an intemediary by the bootstrap scripts 39 // for storing the private key before generating a NodeMachineAccountInfo. 40 type NodeMachineAccountKey struct { 41 PrivateKey encodable.MachineAccountPrivKey 42 } 43 44 // NodeMachineAccountInfo defines the structure for a bootstrapping file containing 45 // private information about the node's machine account. The machine account is used 46 // by the protocol software to interact with Flow as a client autonomously as needed, in 47 // particular to run the DKG and generate root cluster quorum certificates when preparing 48 // for an epoch. 49 type NodeMachineAccountInfo struct { 50 // Address is the flow address of the machine account, not to be confused 51 // with the network address of the node. 52 Address string 53 54 // EncodedPrivateKey is the private key of the machine account 55 EncodedPrivateKey []byte 56 57 // KeyIndex is the index of the key in the associated machine account 58 KeyIndex uint 59 60 // SigningAlgorithm is the algorithm used by the machine account along with 61 // the above private key to create cryptographic signatures 62 SigningAlgorithm sdkcrypto.SignatureAlgorithm 63 64 // HashAlgorithm is the algorithm used for hashing 65 HashAlgorithm sdkcrypto.HashAlgorithm 66 } 67 68 func (info NodeMachineAccountInfo) FlowAddress() flow.Address { 69 // trim 0x-prefix if present 70 addr := info.Address 71 if strings.ToLower(addr[:2]) == "0x" { 72 addr = addr[2:] 73 } 74 return flow.HexToAddress(addr) 75 } 76 77 func (info NodeMachineAccountInfo) SDKAddress() sdk.Address { 78 flowAddr := info.FlowAddress() 79 var sdkAddr sdk.Address 80 copy(sdkAddr[:], flowAddr[:]) 81 return sdkAddr 82 } 83 84 func (info NodeMachineAccountInfo) PrivateKey() (crypto.PrivateKey, error) { 85 sk, err := crypto.DecodePrivateKey(info.SigningAlgorithm, info.EncodedPrivateKey) 86 if err != nil { 87 return nil, fmt.Errorf("could not decode machine account private key: %w", err) 88 } 89 return sk, nil 90 } 91 92 func (info NodeMachineAccountInfo) MustPrivateKey() crypto.PrivateKey { 93 sk, err := info.PrivateKey() 94 if err != nil { 95 panic(err) 96 } 97 return sk 98 } 99 100 // NodeConfig contains configuration information used as input to the 101 // bootstrap process. 102 type NodeConfig struct { 103 // Role is the flow role of the node (ex Collection, Consensus, ...) 104 Role flow.Role 105 106 // Address is the networking address of the node (IP:PORT), not to be 107 // confused with the address of the flow account associated with the node's 108 // machine account. 109 Address string 110 111 // Weight is the weight of the node 112 Weight uint64 113 } 114 115 // decodableNodeConfig provides backward-compatible decoding of old models 116 // which use the Stake field in place of Weight. 117 type decodableNodeConfig struct { 118 Role flow.Role 119 Address string 120 Weight uint64 121 // Stake previously was used in place of the Weight field. 122 Stake uint64 123 } 124 125 func (conf *NodeConfig) UnmarshalJSON(b []byte) error { 126 var decodable decodableNodeConfig 127 err := json.Unmarshal(b, &decodable) 128 if err != nil { 129 return fmt.Errorf("could not decode json: %w", err) 130 } 131 // compat: translate Stake fields to Weight 132 if decodable.Stake != 0 { 133 if decodable.Weight != 0 { 134 return fmt.Errorf("invalid NodeConfig with both Stake and Weight fields") 135 } 136 decodable.Weight = decodable.Stake 137 } 138 conf.Role = decodable.Role 139 conf.Address = decodable.Address 140 conf.Weight = decodable.Weight 141 return nil 142 } 143 144 // NodeInfoPriv defines the canonical structure for encoding private node info. 145 type NodeInfoPriv struct { 146 Role flow.Role 147 Address string 148 NodeID flow.Identifier 149 NetworkPrivKey encodable.NetworkPrivKey 150 StakingPrivKey encodable.StakingPrivKey 151 } 152 153 // NodeInfoPub defines the canonical structure for encoding public node info. 154 type NodeInfoPub struct { 155 Role flow.Role 156 Address string 157 NodeID flow.Identifier 158 Weight uint64 159 NetworkPubKey encodable.NetworkPubKey 160 StakingPubKey encodable.StakingPubKey 161 } 162 163 // decodableNodeInfoPub provides backward-compatible decoding of old models 164 // which use the Stake field in place of Weight. 165 type decodableNodeInfoPub struct { 166 Role flow.Role 167 Address string 168 NodeID flow.Identifier 169 Weight uint64 170 NetworkPubKey encodable.NetworkPubKey 171 StakingPubKey encodable.StakingPubKey 172 // Stake previously was used in place of the Weight field. 173 // Deprecated: supported in decoding for backward-compatibility 174 Stake uint64 175 } 176 177 func (info *NodeInfoPub) UnmarshalJSON(b []byte) error { 178 var decodable decodableNodeInfoPub 179 err := json.Unmarshal(b, &decodable) 180 if err != nil { 181 return fmt.Errorf("could not decode json: %w", err) 182 } 183 // compat: translate Stake fields to Weight 184 if decodable.Stake != 0 { 185 if decodable.Weight != 0 { 186 return fmt.Errorf("invalid NodeInfoPub with both Stake and Weight fields") 187 } 188 decodable.Weight = decodable.Stake 189 } 190 info.Role = decodable.Role 191 info.Address = decodable.Address 192 info.NodeID = decodable.NodeID 193 info.Weight = decodable.Weight 194 info.NetworkPubKey = decodable.NetworkPubKey 195 info.StakingPubKey = decodable.StakingPubKey 196 return nil 197 } 198 199 // NodePrivateKeys is a wrapper for the private keys for a node, comprising all 200 // sensitive information for a node. 201 type NodePrivateKeys struct { 202 StakingKey crypto.PrivateKey 203 NetworkKey crypto.PrivateKey 204 } 205 206 // NodeInfo contains information for a node. This is used during the bootstrapping 207 // process to represent each node. When writing node information to disk, use 208 // `Public` or `Private` to obtain the appropriate canonical structure. 209 // 210 // A NodeInfo instance can contain EITHER public keys OR private keys, not both. 211 // This can be ensured by using only using the provided constructors and NOT 212 // manually constructing an instance. 213 type NodeInfo struct { 214 215 // NodeID is the unique identifier of the node in the network 216 NodeID flow.Identifier 217 218 // Role is the flow role of the node (collection, consensus, etc...) 219 Role flow.Role 220 221 // Address is the networking address of the node (IP:PORT), not to be 222 // confused with the address of the flow account associated with the node's 223 // machine account. 224 Address string 225 226 // Weight is the weight of the node 227 Weight uint64 228 229 // key information is private 230 networkPubKey crypto.PublicKey 231 networkPrivKey crypto.PrivateKey 232 stakingPubKey crypto.PublicKey 233 stakingPrivKey crypto.PrivateKey 234 } 235 236 func NewPublicNodeInfo( 237 nodeID flow.Identifier, 238 role flow.Role, 239 addr string, 240 weight uint64, 241 networkKey crypto.PublicKey, 242 stakingKey crypto.PublicKey, 243 ) NodeInfo { 244 return NodeInfo{ 245 NodeID: nodeID, 246 Role: role, 247 Address: addr, 248 Weight: weight, 249 networkPubKey: networkKey, 250 stakingPubKey: stakingKey, 251 } 252 } 253 254 func NewPrivateNodeInfo( 255 nodeID flow.Identifier, 256 role flow.Role, 257 addr string, 258 weight uint64, 259 networkKey crypto.PrivateKey, 260 stakingKey crypto.PrivateKey, 261 ) NodeInfo { 262 return NodeInfo{ 263 NodeID: nodeID, 264 Role: role, 265 Address: addr, 266 Weight: weight, 267 networkPrivKey: networkKey, 268 stakingPrivKey: stakingKey, 269 networkPubKey: networkKey.PublicKey(), 270 stakingPubKey: stakingKey.PublicKey(), 271 } 272 } 273 274 // Type returns the type of the node info instance. 275 func (node NodeInfo) Type() NodeInfoType { 276 if node.networkPrivKey != nil && node.stakingPrivKey != nil { 277 return NodeInfoTypePrivate 278 } 279 if node.networkPubKey != nil && node.stakingPubKey != nil { 280 return NodeInfoTypePublic 281 } 282 return NodeInfoTypeInvalid 283 } 284 285 func (node NodeInfo) NetworkPubKey() crypto.PublicKey { 286 if node.networkPubKey != nil { 287 return node.networkPubKey 288 } 289 return node.networkPrivKey.PublicKey() 290 } 291 292 func (node NodeInfo) StakingPubKey() crypto.PublicKey { 293 if node.stakingPubKey != nil { 294 return node.stakingPubKey 295 } 296 return node.stakingPrivKey.PublicKey() 297 } 298 299 func (node NodeInfo) PrivateKeys() (*NodePrivateKeys, error) { 300 if node.Type() != NodeInfoTypePrivate { 301 return nil, ErrMissingPrivateInfo 302 } 303 return &NodePrivateKeys{ 304 StakingKey: node.stakingPrivKey, 305 NetworkKey: node.networkPrivKey, 306 }, nil 307 } 308 309 // Private returns the canonical private encodable structure. 310 func (node NodeInfo) Private() (NodeInfoPriv, error) { 311 if node.Type() != NodeInfoTypePrivate { 312 return NodeInfoPriv{}, ErrMissingPrivateInfo 313 } 314 315 return NodeInfoPriv{ 316 Role: node.Role, 317 Address: node.Address, 318 NodeID: node.NodeID, 319 NetworkPrivKey: encodable.NetworkPrivKey{PrivateKey: node.networkPrivKey}, 320 StakingPrivKey: encodable.StakingPrivKey{PrivateKey: node.stakingPrivKey}, 321 }, nil 322 } 323 324 // Public returns the canonical public encodable structure 325 func (node NodeInfo) Public() NodeInfoPub { 326 return NodeInfoPub{ 327 Role: node.Role, 328 Address: node.Address, 329 NodeID: node.NodeID, 330 Weight: node.Weight, 331 NetworkPubKey: encodable.NetworkPubKey{PublicKey: node.NetworkPubKey()}, 332 StakingPubKey: encodable.StakingPubKey{PublicKey: node.StakingPubKey()}, 333 } 334 } 335 336 // PartnerPublic returns the public data for a partner node. 337 func (node NodeInfo) PartnerPublic() PartnerNodeInfoPub { 338 return PartnerNodeInfoPub{ 339 Role: node.Role, 340 Address: node.Address, 341 NodeID: node.NodeID, 342 NetworkPubKey: encodable.NetworkPubKey{PublicKey: node.NetworkPubKey()}, 343 StakingPubKey: encodable.StakingPubKey{PublicKey: node.StakingPubKey()}, 344 } 345 } 346 347 // Identity returns the node info as a public Flow identity. 348 func (node NodeInfo) Identity() *flow.Identity { 349 identity := &flow.Identity{ 350 NodeID: node.NodeID, 351 Address: node.Address, 352 Role: node.Role, 353 Weight: node.Weight, 354 StakingPubKey: node.StakingPubKey(), 355 NetworkPubKey: node.NetworkPubKey(), 356 } 357 return identity 358 } 359 360 // NodeInfoFromIdentity converts an identity to a public NodeInfo 361 func NodeInfoFromIdentity(identity *flow.Identity) NodeInfo { 362 return NewPublicNodeInfo( 363 identity.NodeID, 364 identity.Role, 365 identity.Address, 366 identity.Weight, 367 identity.NetworkPubKey, 368 identity.StakingPubKey) 369 } 370 371 func PrivateNodeInfoFromIdentity(identity *flow.Identity, networkKey, stakingKey crypto.PrivateKey) NodeInfo { 372 return NewPrivateNodeInfo( 373 identity.NodeID, 374 identity.Role, 375 identity.Address, 376 identity.Weight, 377 networkKey, 378 stakingKey, 379 ) 380 } 381 382 func FilterByRole(nodes []NodeInfo, role flow.Role) []NodeInfo { 383 var filtered []NodeInfo 384 for _, node := range nodes { 385 if node.Role != role { 386 continue 387 } 388 filtered = append(filtered, node) 389 } 390 return filtered 391 } 392 393 // Sort sorts the NodeInfo list using the given ordering. 394 func Sort(nodes []NodeInfo, order flow.IdentityOrder) []NodeInfo { 395 dup := make([]NodeInfo, len(nodes)) 396 copy(dup, nodes) 397 sort.Slice(dup, func(i, j int) bool { 398 return order(dup[i].Identity(), dup[j].Identity()) 399 }) 400 return dup 401 } 402 403 func ToIdentityList(nodes []NodeInfo) flow.IdentityList { 404 il := make(flow.IdentityList, 0, len(nodes)) 405 for _, node := range nodes { 406 il = append(il, node.Identity()) 407 } 408 return il 409 } 410 411 func ToPublicNodeInfoList(nodes []NodeInfo) []NodeInfoPub { 412 pub := make([]NodeInfoPub, 0, len(nodes)) 413 for _, node := range nodes { 414 pub = append(pub, node.Public()) 415 } 416 return pub 417 }