github.com/kotalco/kotal@v0.3.0/clients/ethereum/nethermind_client.go (about)

     1  package ethereum
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	ethereumv1alpha1 "github.com/kotalco/kotal/apis/ethereum/v1alpha1"
     9  	"github.com/kotalco/kotal/controllers/shared"
    10  	corev1 "k8s.io/api/core/v1"
    11  )
    12  
    13  const (
    14  	// NethermindHomeDir is nethermind docker image home directory
    15  	NethermindHomeDir = "/home/nethermind"
    16  )
    17  
    18  // NethermindClient is nethermind client
    19  // https://github.com/NethermindEth/nethermind
    20  type NethermindClient struct {
    21  	*ParityGenesis
    22  	node *ethereumv1alpha1.Node
    23  }
    24  
    25  // HomeDir returns besu client home directory
    26  func (n *NethermindClient) HomeDir() string {
    27  	return NethermindHomeDir
    28  }
    29  
    30  func (n *NethermindClient) Command() []string {
    31  	return nil
    32  }
    33  
    34  func (n *NethermindClient) Env() []corev1.EnvVar {
    35  	return nil
    36  }
    37  
    38  // Args returns command line arguments required for client run
    39  // NOTE:
    40  // - Network ID can be set in genesis config
    41  func (n *NethermindClient) Args() (args []string) {
    42  
    43  	node := n.node
    44  
    45  	args = append(args, NethermindDataPath, shared.PathData(n.HomeDir()))
    46  	args = append(args, NethermindP2PPort, fmt.Sprintf("%d", node.Spec.P2PPort))
    47  	args = append(args, NethermindLogging, strings.ToUpper(string(node.Spec.Logging)))
    48  
    49  	if node.Spec.NodePrivateKeySecretName != "" {
    50  		// use enode private key in binary format
    51  		// that has been converted using nethermind_convert_enode_privatekey.sh script
    52  		args = append(args, NethermindNodePrivateKey, fmt.Sprintf("%s/kotal_nodekey", shared.PathData(n.HomeDir())))
    53  	}
    54  
    55  	if len(node.Spec.StaticNodes) != 0 {
    56  		args = append(args, NethermindStaticNodesFile, fmt.Sprintf("%s/static-nodes.json", shared.PathConfig(n.HomeDir())))
    57  	}
    58  
    59  	if len(node.Spec.Bootnodes) != 0 {
    60  		bootnodes := []string{}
    61  		for _, bootnode := range node.Spec.Bootnodes {
    62  			bootnodes = append(bootnodes, string(bootnode))
    63  		}
    64  		args = append(args, NethermindBootnodes, strings.Join(bootnodes, ","))
    65  	}
    66  
    67  	if node.Spec.Genesis == nil {
    68  		args = append(args, NethermindNetwork, node.Spec.Network)
    69  	} else {
    70  		// use empty config, because nethermind uses mainnet.cfg by default which can shadow some settings here
    71  		args = append(args, NethermindNetwork, fmt.Sprintf("%s/empty.cfg", shared.PathConfig(n.HomeDir())))
    72  		args = append(args, NethermindGenesisFile, fmt.Sprintf("%s/genesis.json", shared.PathConfig(n.HomeDir())))
    73  		args = append(args, NethermindDiscoveryEnabled, "false")
    74  	}
    75  
    76  	switch node.Spec.SyncMode {
    77  	case ethereumv1alpha1.FullSynchronization:
    78  		args = append(args, NethermindFastSync, "false")
    79  		args = append(args, NethermindFastBlocks, "false")
    80  		args = append(args, NethermindDownloadBodiesInFastSync, "false")
    81  		args = append(args, NethermindDownloadReceiptsInFastSync, "false")
    82  	case ethereumv1alpha1.FastSynchronization:
    83  		args = append(args, NethermindFastSync, "true")
    84  		args = append(args, NethermindFastBlocks, "true")
    85  		args = append(args, NethermindDownloadBodiesInFastSync, "true")
    86  		args = append(args, NethermindDownloadReceiptsInFastSync, "true")
    87  	}
    88  
    89  	if node.Spec.Miner {
    90  		args = append(args, NethermindMiningEnabled, "true")
    91  		args = append(args, NethermindMinerCoinbase, string(node.Spec.Coinbase))
    92  		args = append(args, NethermindUnlockAccounts, fmt.Sprintf("[%s]", node.Spec.Coinbase))
    93  		args = append(args, NethermindPasswordFiles, fmt.Sprintf("[%s/account.password]", shared.PathSecrets(n.HomeDir())))
    94  	}
    95  
    96  	if node.Spec.RPC {
    97  		args = append(args, NethermindRPCHTTPEnabled, "true")
    98  		args = append(args, NethermindRPCHTTPPort, fmt.Sprintf("%d", node.Spec.RPCPort))
    99  		args = append(args, NethermindRPCHTTPHost, shared.Host(node.Spec.RPC))
   100  		// JSON-RPC API
   101  		apis := []string{}
   102  		for _, api := range node.Spec.RPCAPI {
   103  			apis = append(apis, string(api))
   104  		}
   105  		commaSeperatedAPIs := strings.Join(apis, ",")
   106  		args = append(args, NethermindRPCHTTPAPI, commaSeperatedAPIs)
   107  	}
   108  
   109  	if node.Spec.Engine {
   110  		args = append(args, NethermindRPCEnginePort, fmt.Sprintf("%d", node.Spec.EnginePort))
   111  		jwtSecretPath := fmt.Sprintf("%s/jwt.secret", shared.PathSecrets(n.HomeDir()))
   112  		args = append(args, NethermindRPCJwtSecretFile, jwtSecretPath)
   113  	}
   114  	args = append(args, NethermindRPCEngineHost, shared.Host(node.Spec.Engine))
   115  
   116  	if node.Spec.WS {
   117  		args = append(args, NethermindRPCWSEnabled, "true")
   118  		args = append(args, NethermindRPCWSPort, fmt.Sprintf("%d", node.Spec.WSPort))
   119  		// no option for ws host, ws uses same http host as JSON-RPC
   120  		// nethermind ws reuses enabled JSON-RPC modules
   121  	}
   122  
   123  	return args
   124  }
   125  
   126  // Genesis returns genesis config parameter
   127  func (p *NethermindClient) Genesis() (string, error) {
   128  	return p.ParityGenesis.Genesis(p.node)
   129  }
   130  
   131  // EncodeStaticNodes returns the static nodes, one per line
   132  func (n *NethermindClient) EncodeStaticNodes() string {
   133  
   134  	if len(n.node.Spec.StaticNodes) == 0 {
   135  		return "[]"
   136  	}
   137  
   138  	encoded, _ := json.Marshal(n.node.Spec.StaticNodes)
   139  	return string(encoded)
   140  }