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