github.com/onflow/flow-go@v0.33.17/cmd/utils.go (about)

     1  package cmd
     2  
     3  import (
     4  	"encoding/hex"
     5  	"encoding/json"
     6  	"fmt"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/libp2p/go-libp2p/core/peer"
    11  	"github.com/rs/zerolog"
    12  
    13  	"github.com/onflow/flow-go/crypto"
    14  	"github.com/onflow/flow-go/model/bootstrap"
    15  	"github.com/onflow/flow-go/model/flow"
    16  	"github.com/onflow/flow-go/module"
    17  	"github.com/onflow/flow-go/module/id"
    18  	"github.com/onflow/flow-go/network/p2p"
    19  	"github.com/onflow/flow-go/network/p2p/cache"
    20  	p2plogging "github.com/onflow/flow-go/network/p2p/logging"
    21  	"github.com/onflow/flow-go/network/p2p/translator"
    22  	"github.com/onflow/flow-go/network/p2p/unicast/protocols"
    23  	"github.com/onflow/flow-go/state/protocol/inmem"
    24  	"github.com/onflow/flow-go/utils/io"
    25  )
    26  
    27  // loadRootProtocolSnapshot loads the root protocol snapshot from disk
    28  func loadRootProtocolSnapshot(dir string) (*inmem.Snapshot, error) {
    29  	path := filepath.Join(dir, bootstrap.PathRootProtocolStateSnapshot)
    30  	data, err := io.ReadFile(path)
    31  	if err != nil {
    32  		return nil, fmt.Errorf("could not read root snapshot (path=%s): %w", path, err)
    33  	}
    34  
    35  	var snapshot inmem.EncodableSnapshot
    36  	err = json.Unmarshal(data, &snapshot)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	return inmem.SnapshotFromEncodable(snapshot), nil
    42  }
    43  
    44  // LoadPrivateNodeInfo the private info for this node from disk (e.g., private staking/network keys).
    45  func LoadPrivateNodeInfo(dir string, myID flow.Identifier) (*bootstrap.NodeInfoPriv, error) {
    46  	path := filepath.Join(dir, fmt.Sprintf(bootstrap.PathNodeInfoPriv, myID))
    47  	data, err := io.ReadFile(path)
    48  	if err != nil {
    49  		return nil, fmt.Errorf("could not read private node info (path=%s): %w", path, err)
    50  	}
    51  	var info bootstrap.NodeInfoPriv
    52  	err = json.Unmarshal(data, &info)
    53  	return &info, err
    54  }
    55  
    56  func LoadNetworkPrivateKey(dir string, myID flow.Identifier) (crypto.PrivateKey, error) {
    57  	path := filepath.Join(dir, fmt.Sprintf(filepath.Join(bootstrap.DirPrivateRoot,
    58  		"private-node-info_%v/network_private_key"), myID))
    59  	data, err := io.ReadFile(path)
    60  	if err != nil {
    61  		return nil, fmt.Errorf("could not read private node info (path=%s): %w", path, err)
    62  	}
    63  
    64  	keyBytes, err := hex.DecodeString(strings.Trim(string(data), "\n "))
    65  	if err != nil {
    66  		return nil, fmt.Errorf("could not hex decode networking key (path=%s): %w", path, err)
    67  	}
    68  
    69  	networkingKey, err := crypto.DecodePrivateKey(crypto.ECDSASecp256k1, keyBytes)
    70  	if err != nil {
    71  		return nil, fmt.Errorf("could not decode networking key (path=%s): %w", path, err)
    72  	}
    73  	return networkingKey, nil
    74  }
    75  
    76  // loadSecretsEncryptionKey loads the encryption key for the secrets database.
    77  // If the file does not exist, returns os.ErrNotExist.
    78  func loadSecretsEncryptionKey(dir string, myID flow.Identifier) ([]byte, error) {
    79  	path := filepath.Join(dir, fmt.Sprintf(bootstrap.PathSecretsEncryptionKey, myID))
    80  	data, err := io.ReadFile(path)
    81  	if err != nil {
    82  		return nil, fmt.Errorf("could not read secrets db encryption key (path=%s): %w", path, err)
    83  	}
    84  	return data, nil
    85  }
    86  
    87  func rateLimiterPeerFilter(rateLimiter p2p.RateLimiter) p2p.PeerFilter {
    88  	return func(p peer.ID) error {
    89  		if rateLimiter.IsRateLimited(p) {
    90  			return fmt.Errorf("peer is rate limited")
    91  		}
    92  
    93  		return nil
    94  	}
    95  }
    96  
    97  // BootstrapIdentities converts the bootstrap node addresses and keys to a Flow Identity list where
    98  // each Flow Identity is initialized with the passed address, the networking key
    99  // and the Node ID set to ZeroID, role set to Access, 0 stake and no staking key.
   100  func BootstrapIdentities(addresses []string, keys []string) (flow.IdentityList, error) {
   101  	if len(addresses) != len(keys) {
   102  		return nil, fmt.Errorf("number of addresses and keys provided for the boostrap nodes don't match")
   103  	}
   104  
   105  	ids := make(flow.IdentityList, len(addresses))
   106  	for i, address := range addresses {
   107  		bytes, err := hex.DecodeString(keys[i])
   108  		if err != nil {
   109  			return nil, fmt.Errorf("failed to decode secured GRPC server public key hex %w", err)
   110  		}
   111  
   112  		publicFlowNetworkingKey, err := crypto.DecodePublicKey(crypto.ECDSAP256, bytes)
   113  		if err != nil {
   114  			return nil, fmt.Errorf("failed to get public flow networking key could not decode public key bytes %w", err)
   115  		}
   116  
   117  		// create the identity of the peer by setting only the relevant fields
   118  		ids[i] = &flow.Identity{
   119  			NodeID:        flow.ZeroID, // the NodeID is the hash of the staking key and for the public network it does not apply
   120  			Address:       address,
   121  			Role:          flow.RoleAccess, // the upstream node has to be an access node
   122  			NetworkPubKey: publicFlowNetworkingKey,
   123  		}
   124  	}
   125  	return ids, nil
   126  }
   127  
   128  func CreatePublicIDTranslatorAndIdentifierProvider(
   129  	logger zerolog.Logger,
   130  	networkKey crypto.PrivateKey,
   131  	sporkID flow.Identifier,
   132  	getLibp2pNode func() p2p.LibP2PNode,
   133  	idCache *cache.ProtocolStateIDCache,
   134  ) (
   135  	p2p.IDTranslator,
   136  	func() module.IdentifierProvider,
   137  	error,
   138  ) {
   139  	idTranslator := translator.NewHierarchicalIDTranslator(idCache, translator.NewPublicNetworkIDTranslator())
   140  
   141  	peerID, err := peerIDFromNetworkKey(networkKey)
   142  	if err != nil {
   143  		return nil, nil, fmt.Errorf("could not get peer ID from network key: %w", err)
   144  	}
   145  	// use the default identifier provider
   146  	factory := func() module.IdentifierProvider {
   147  		return id.NewCustomIdentifierProvider(func() flow.IdentifierList {
   148  			pids := getLibp2pNode().GetPeersForProtocol(protocols.FlowProtocolID(sporkID))
   149  			result := make(flow.IdentifierList, 0, len(pids))
   150  
   151  			for _, pid := range pids {
   152  				// exclude own Identifier
   153  				if pid == peerID {
   154  					continue
   155  				}
   156  
   157  				if flowID, err := idTranslator.GetFlowID(pid); err != nil {
   158  					// TODO: this is an instance of "log error and continue with best effort" anti-pattern
   159  					logger.Fatal().Err(err).Str("peer", p2plogging.PeerId(pid)).Msg("failed to translate to Flow ID")
   160  				} else {
   161  					result = append(result, flowID)
   162  				}
   163  			}
   164  
   165  			if len(result) == 0 {
   166  				logger.Error().Msgf("empty identifier list, pids: %v", pids)
   167  			}
   168  
   169  			return result
   170  		})
   171  	}
   172  
   173  	return idTranslator, factory, nil
   174  }