From 2da9be1e7a58430325c898ee98d0c7a029209852 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Wed, 12 Dec 2018 11:26:27 -0500 Subject: [PATCH 01/14] add local config path flag with defaults --- Gopkg.lock | 16 ++++++++++++++++ cmd/rpcserver.go | 13 ++++++++++++- cmd/shell.go | 3 ++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 0c026fc7..cd8b3a60 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -28,6 +28,21 @@ pruneopts = "" revision = "5312a61534124124185d41f09206b9fef1d88403" +[[projects]] + digest = "1:1c8ee7543ae60103ae543f79e6044d768e6de6cfaa245c53e45f3681c7f682a0" + name = "github.com/awalterschulze/gographviz" + packages = [ + ".", + "ast", + "internal/errors", + "internal/lexer", + "internal/parser", + "internal/token", + ] + pruneopts = "" + revision = "c84395e536e1a1199093a4e6253d1bee99e4cd2a" + version = "v2.0" + [[projects]] branch = "master" digest = "1:542be9fb8d738302988a3733cd1391f5909c3b580825df99a9fae723f493e2bf" @@ -886,6 +901,7 @@ analyzer-version = 1 input-imports = [ "github.com/abiosoft/ishell", + "github.com/awalterschulze/gographviz", "github.com/btcsuite/btcutil/base58", "github.com/dedis/kyber", "github.com/dedis/kyber/pairing/bn256", diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index a97b5e8b..7381a5cf 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -3,6 +3,7 @@ package cmd import ( "context" "encoding/json" + "os/user" "strings" "time" @@ -19,6 +20,7 @@ var ( certFile string keyFile string localNetworkNodeCount int + localConfigPath string ) func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { @@ -116,11 +118,20 @@ var rpcServerCmd = &cobra.Command{ }, } +func defaultCfgPath() string { + usr, err := user.Current() + if err != nil { + log.Warn("Error finding user: %v", err) + } + return filepath.Join(usr.HomeDir, ".tupelo/local_network") +} + func init() { rootCmd.AddCommand(rpcServerCmd) rpcServerCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which public keys to bootstrap the notary groups with") - rpcServerCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 0, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") + rpcServerCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") rpcServerCmd.Flags().BoolVarP(&tls, "tls", "t", false, "Encrypt connections with TLS/SSL") + rpcServerCmd.Flags().StringVarP(&localConfigPath, "config-path", "c", defaultCfgPath(), "Local network configuration") rpcServerCmd.Flags().StringVarP(&certFile, "tls-cert", "C", "", "TLS certificate file") rpcServerCmd.Flags().StringVarP(&keyFile, "tls-key", "K", "", "TLS private key file") } diff --git a/cmd/shell.go b/cmd/shell.go index 7d53facc..fe0c94d7 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -36,5 +36,6 @@ func init() { shellCmd.Flags().StringVarP(&shellName, "name", "n", "", "the name to use for the wallet") shellCmd.MarkFlagRequired("name") shellCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") - shellCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 0, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") + shellCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") + shellCmd.Flags().StringVarP(&localConfigPath, "config-path", "c", defaultCfgPath(), "Local network configuration") } From ea7814763d2f6237cebf74cb51201a06d59a86d4 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Thu, 13 Dec 2018 16:05:19 -0500 Subject: [PATCH 02/14] factor out functions that write generated keysets --- cmd/generateNodeKeys.go | 84 ++++++++++++++++++++++++++--------------- cmd/root.go | 18 ++------- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index 64666653..70f0e118 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -20,7 +20,7 @@ var ( generateNodeKeysPath string ) -func generateKeySet(numberOfKeys int) (privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, err error) { +func generateKeySets(numberOfKeys int) (privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, err error) { for i := 1; i <= numberOfKeys; i++ { blsKey, err := bls.NewSignKey() if err != nil { @@ -50,48 +50,72 @@ func generateKeySet(numberOfKeys int) (privateKeys []*PrivateKeySet, publicKeys return privateKeys, publicKeys, err } +func printTextKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet) { + for i := 1; i <= len(privateKeys); i++ { + fmt.Printf("================ Key %v ================\n", i) + fmt.Printf( + "bls: '%v'\nbls public: '%v'\necdsa: '%v'\necdsa public: '%v'\npeer id: '%v'", + privateKeys[0].BlsHexPrivateKey, + publicKeys[0].BlsHexPublicKey, + privateKeys[0].EcdsaHexPrivateKey, + publicKeys[0].EcdsaHexPublicKey, + publicKeys[0].PeerIDBase58Key, + ) + } +} + +func privateKeyFile(configPath string) string { + return filepath.Join(configPath, "private-keys.json") +} + +func publicKeyFile(configPath string) string { + return filepath.Join(configPath, "public-keys.json") +} + +func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, path string) error { + publicKeyJson, err := json.Marshal(publicKeys) + if err != nil { + return fmt.Errorf("Error marshaling public keys: %v", err) + } + + pubPath := publicKeyFile(path) + err = ioutil.WriteFile(pubPath, publicKeyJson, 0644) + if err != nil { + return fmt.Errorf("Error writing to path '%v': %v", pubPath, err) + } + + privateKeyJson, err := json.Marshal(privateKeys) + if err != nil { + return fmt.Errorf("Error marshaling private keys: %v", err) + } + + prvPath := privateKeyFile(path) + err = ioutil.WriteFile(prvPath, privateKeyJson, 0644) + if err != nil { + return fmt.Errorf("Error writing to path '%v': %v", prvPath, err) + } + + return nil +} + // generateNodeKeysCmd represents the generateNodeKeys command var generateNodeKeysCmd = &cobra.Command{ Use: "generate-node-keys", Short: "Generate a new set of node keys", Long: ``, Run: func(cmd *cobra.Command, args []string) { - privateKeys, publicKeys, err := generateKeySet(generateNodeKeysCount) - + privateKeys, publicKeys, err := generateKeySets(generateNodeKeysCount) if err != nil { - panic(err) + panic(fmt.Sprintf("error generating key sets: %v", err)) } switch generateNodeKeysOutput { case "text": - for i := 1; i <= len(privateKeys); i++ { - fmt.Printf("================ Key %v ================\n", i) - fmt.Printf( - "bls: '%v'\nbls public: '%v'\necdsa: '%v'\necdsa public: '%v'\npeer id: '%v'", - privateKeys[0].BlsHexPrivateKey, - publicKeys[0].BlsHexPublicKey, - privateKeys[0].EcdsaHexPrivateKey, - publicKeys[0].EcdsaHexPublicKey, - publicKeys[0].PeerIDBase58Key, - ) - } + printTextKeys(privateKeys, publicKeys) case "json-file": - publicKeyJson, err := json.Marshal(publicKeys) - if err != nil { - panic(fmt.Sprintf("error writing json %v", err)) - } - err = ioutil.WriteFile(filepath.Join(generateNodeKeysPath, "public-keys.json"), publicKeyJson, 0644) - if err != nil { - panic(fmt.Sprintf("error writing file %v", err)) - } - - privateKeyJson, err := json.Marshal(privateKeys) - if err != nil { - panic(fmt.Sprintf("error writing json %v", err)) - } - err = ioutil.WriteFile(filepath.Join(generateNodeKeysPath, "private-keys.json"), privateKeyJson, 0644) + err := writeJSONKeys(privateKeys, publicKeys, generateNodeKeysPath) if err != nil { - panic(fmt.Sprintf("error writing file %v", err)) + panic(fmt.Sprintf("error writing json file: %v", err)) } default: panic(fmt.Sprintf("output=%v type is not supported", generateNodeKeysOutput)) diff --git a/cmd/root.go b/cmd/root.go index e9a95fa4..50a17fee 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -63,19 +63,13 @@ type PrivateKeySet struct { // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ Use: "tupelo", - Short: "A brief description of your application", - Long: `A longer description that spans multiple lines and likely contains -examples and usage of using your application. For example: - -Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, + Short: "Tupelo interface", + Long: `Tupelo is a distributed ledger optimized for ownership`, PersistentPreRun: func(cmd *cobra.Command, args []string) { if bootstrapPublicKeysFile != "" { - var err error - bootstrapPublicKeys, err = loadPublicKeyFile(bootstrapPublicKeysFile) + bootstrapPublicKeys, err := loadPublicKeyFile(bootstrapPublicKeysFile) if err != nil { - panic("Error loading public keys file") + panic(fmt.Sprintf("Error loading public keys: %v", err)) } } @@ -90,10 +84,6 @@ to quickly create a Cobra application.`, } }, - - // Uncomment the following line if your bare application - // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. From a28ff31586a0ff89721a7a6c09cfb129c455bb83 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 14 Dec 2018 02:20:47 -0500 Subject: [PATCH 03/14] load key sets from the configuration path --- cmd/root.go | 3 +- cmd/rpcserver.go | 134 ++++++++++++++++++++++++++++++++++++++--------- cmd/shell.go | 2 +- cmd/testnode.go | 48 ----------------- 4 files changed, 111 insertions(+), 76 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 50a17fee..c7a3c8fd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -67,7 +67,8 @@ var rootCmd = &cobra.Command{ Long: `Tupelo is a distributed ledger optimized for ownership`, PersistentPreRun: func(cmd *cobra.Command, args []string) { if bootstrapPublicKeysFile != "" { - bootstrapPublicKeys, err := loadPublicKeyFile(bootstrapPublicKeysFile) + var err error + bootstrapPublicKeys, err = loadPublicKeyFile(bootstrapPublicKeysFile) if err != nil { panic(fmt.Sprintf("Error loading public keys: %v", err)) } diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index 7381a5cf..c659c32f 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -3,10 +3,15 @@ package cmd import ( "context" "encoding/json" + "fmt" + "io/ioutil" + "os" "os/user" + "path/filepath" "strings" "time" + "github.com/ethereum/go-ethereum/log" "github.com/quorumcontrol/storage" "github.com/quorumcontrol/tupelo/gossip2" "github.com/quorumcontrol/tupelo/gossip2client" @@ -15,53 +20,104 @@ import ( "github.com/spf13/cobra" ) -var ( - tls bool - certFile string - keyFile string - localNetworkNodeCount int - localConfigPath string -) -func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { - var jsonLoadedKeys []*PrivateKeySet +func expandHomePath(path string) (string, error) { + currentUser, err := user.Current() + if err != nil { + return "", fmt.Errorf("error getting current user: %v", err) + } + homeDir := currentUser.HomeDir - jsonBytes, err := loadJSON(path) + if path[:2] == "~/" { + path = filepath.Join(homeDir, path[2:]) + } + return path, nil +} + +func loadJSON(path string) ([]byte, error) { + if path == "" { + return nil, nil + } + modPath, err := expandHomePath(path) if err != nil { return nil, err } - - err = json.Unmarshal(jsonBytes, &jsonLoadedKeys) + _, err = os.Stat(modPath) if err != nil { return nil, err } - return jsonLoadedKeys, nil + return ioutil.ReadFile(modPath) } -func panicWithoutTLSOpts() { - if certFile == "" || keyFile == "" { - var msg strings.Builder - if certFile == "" { - msg.WriteString("Missing certificate file path. ") - msg.WriteString("Please supply with the -C flag. ") +func loadKeyFile(keySet interface{}, path string) error { + jsonBytes, err := loadJSON(path) + if err != nil { + return err + } + + err = json.Unmarshal(jsonBytes, keySet) + if err != nil { + return err + } + + return nil +} + +func loadPublicKeyFile(path string) ([]*PublicKeySet, error) { + var keySet []*PublicKeySet + err := loadKeyFile(&keySet, publicKeyFile(path)) + + return keySet, err +} + +func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { + var keySet []*PrivateKeySet + err := loadKeyFile(&keySet, privateKeyFile(path)) + + return keySet, err +} + +func loadKeys(path string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { + privateKeys, err := loadPrivateKeyFile(path) + if err != nil { + return nil, nil, fmt.Errorf("Error loading private keys: %v", err) + } + + publicKeys, err := loadPublicKeyFile(path) + if err != nil { + return nil, nil, fmt.Errorf("Error loading public keys: %v", err) + } + + savedKeyCount := len(privateKeys) + if savedKeyCount < num { + extraPrivateKeys, extraPublicKeys, err := generateKeySets(num - savedKeyCount) + if err != nil { + return nil, nil, fmt.Errorf("Error generating extra node keys: %v", err) } - if keyFile == "" { - msg.WriteString("Missing key file path. ") - msg.WriteString("Please supply with the -K flag. ") + combinedPrivateKeys := append(privateKeys, extraPrivateKeys...) + combinedPublicKeys := append(publicKeys, extraPublicKeys...) + + err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, path) + if err != nil { + return nil, nil, fmt.Errorf("Error writing extra node keys: %v", err) } - panic(msg.String()) + return combinedPrivateKeys, combinedPublicKeys, nil + } else if savedKeyCount > num { + return privateKeys[:num], publicKeys[:num], nil + } else { + return privateKeys, publicKeys, nil } } -func setupLocalNetwork(ctx context.Context) (bootstrapAddrs []string) { +func setupLocalNetwork(ctx context.Context, configPath string, nodeCount int) (bootstrapAddrs []string) { var err error var publicKeys []*PublicKeySet var privateKeys []*PrivateKeySet - privateKeys, publicKeys, err = generateKeySet(localNetworkNodeCount) + privateKeys, publicKeys, err = loadKeys(configPath, nodeCount) if err != nil { panic("Can't generate node keys") } @@ -96,15 +152,33 @@ func bootstrapAddresses(bootstrapHost p2p.Node) []string { return nil } +func panicWithoutTLSOpts() { + if certFile == "" || keyFile == "" { + var msg strings.Builder + if certFile == "" { + msg.WriteString("Missing certificate file path. ") + msg.WriteString("Please supply with the -C flag. ") + } + + if keyFile == "" { + msg.WriteString("Missing key file path. ") + msg.WriteString("Please supply with the -K flag. ") + } + + panic(msg.String()) + } +} + var rpcServerCmd = &cobra.Command{ Use: "rpc-server", Short: "Launches a Tupelo RPC Server", Run: func(cmd *cobra.Command, args []string) { + bootstrapAddrs := p2p.BootstrapNodes() if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx) + bootstrapAddrs = setupLocalNetwork(ctx, localConfigPath, localNetworkNodeCount) } notaryGroup := setupNotaryGroup(storage.NewMemStorage()) @@ -118,6 +192,14 @@ var rpcServerCmd = &cobra.Command{ }, } +var ( + tls bool + certFile string + keyFile string + localNetworkNodeCount int + localConfigPath string +) + func defaultCfgPath() string { usr, err := user.Current() if err != nil { diff --git a/cmd/shell.go b/cmd/shell.go index fe0c94d7..96fcaed4 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -22,7 +22,7 @@ var shellCmd = &cobra.Command{ if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx) + bootstrapAddrs = setupLocalNetwork(ctx, localConfigPath, localNetworkNodeCount) } group := setupNotaryGroup(storage.NewMemStorage()) diff --git a/cmd/testnode.go b/cmd/testnode.go index e3e21a21..044f3dfb 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -17,12 +17,9 @@ package cmd import ( "context" "crypto/ecdsa" - "encoding/json" "fmt" - "io/ioutil" "os" "os/signal" - "os/user" "path/filepath" "syscall" "time" @@ -46,51 +43,6 @@ var ( testnodePort int ) -func expandHomePath(path string) (string, error) { - currentUser, err := user.Current() - if err != nil { - return "", fmt.Errorf("error getting current user: %v", err) - } - homeDir := currentUser.HomeDir - - if path[:2] == "~/" { - path = filepath.Join(homeDir, path[2:]) - } - return path, nil -} - -func loadJSON(path string) ([]byte, error) { - if path == "" { - return nil, nil - } - modPath, err := expandHomePath(path) - if err != nil { - return nil, err - } - _, err = os.Stat(modPath) - if err != nil { - return nil, err - } - - return ioutil.ReadFile(modPath) -} - -func loadPublicKeyFile(path string) ([]*PublicKeySet, error) { - var jsonLoadedKeys []*PublicKeySet - - jsonBytes, err := loadJSON(path) - if err != nil { - return nil, err - } - - err = json.Unmarshal(jsonBytes, &jsonLoadedKeys) - if err != nil { - return nil, err - } - - return jsonLoadedKeys, nil -} - func bootstrapMembers(keys []*PublicKeySet) (members []*consensus.RemoteNode) { for _, keySet := range keys { blsPubKey := consensus.PublicKey{ From c405a6b1369a1a9baa590bed51593e26864f7a70 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 14 Dec 2018 07:25:47 -0500 Subject: [PATCH 04/14] create files/directories where necessary --- cmd/generateNodeKeys.go | 12 ++++++++++++ cmd/rpcserver.go | 37 +++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index 70f0e118..5c37c9da 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" "path/filepath" "github.com/ethereum/go-ethereum/common/hexutil" @@ -64,6 +65,15 @@ func printTextKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet) { } } +func createDirIfNotExist(dir string) { + if _, err := os.Stat(dir); os.IsNotExist(err) { + err = os.MkdirAll(dir, 0700) + if err != nil { + panic(fmt.Sprintf("error creating directory: %v", err)) + } + } +} + func privateKeyFile(configPath string) string { return filepath.Join(configPath, "private-keys.json") } @@ -73,6 +83,8 @@ func publicKeyFile(configPath string) string { } func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, path string) error { + createDirIfNotExist(path) + publicKeyJson, err := json.Marshal(publicKeys) if err != nil { return fmt.Errorf("Error marshaling public keys: %v", err) diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index c659c32f..ad23b3ad 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -20,6 +20,17 @@ import ( "github.com/spf13/cobra" ) +func filePathExists(path string) bool { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return false + } else { + panic(err) + } + } else { + return true + } +} func expandHomePath(path string) (string, error) { currentUser, err := user.Current() @@ -66,14 +77,24 @@ func loadKeyFile(keySet interface{}, path string) error { func loadPublicKeyFile(path string) ([]*PublicKeySet, error) { var keySet []*PublicKeySet - err := loadKeyFile(&keySet, publicKeyFile(path)) + var err error + + pubPath := publicKeyFile(path) + if filePathExists(pubPath) { + err = loadKeyFile(&keySet, pubPath) + } return keySet, err } func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { var keySet []*PrivateKeySet - err := loadKeyFile(&keySet, privateKeyFile(path)) + var err error + + prvPath := privateKeyFile(path) + if filePathExists(prvPath) { + err = loadKeyFile(&keySet, prvPath) + } return keySet, err } @@ -81,19 +102,19 @@ func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { func loadKeys(path string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { privateKeys, err := loadPrivateKeyFile(path) if err != nil { - return nil, nil, fmt.Errorf("Error loading private keys: %v", err) + return nil, nil, fmt.Errorf("error loading private keys: %v", err) } publicKeys, err := loadPublicKeyFile(path) if err != nil { - return nil, nil, fmt.Errorf("Error loading public keys: %v", err) + return nil, nil, fmt.Errorf("error loading public keys: %v", err) } savedKeyCount := len(privateKeys) if savedKeyCount < num { extraPrivateKeys, extraPublicKeys, err := generateKeySets(num - savedKeyCount) if err != nil { - return nil, nil, fmt.Errorf("Error generating extra node keys: %v", err) + return nil, nil, fmt.Errorf("error generating extra node keys: %v", err) } combinedPrivateKeys := append(privateKeys, extraPrivateKeys...) @@ -101,7 +122,7 @@ func loadKeys(path string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, path) if err != nil { - return nil, nil, fmt.Errorf("Error writing extra node keys: %v", err) + return nil, nil, fmt.Errorf("error writing extra node keys: %v", err) } return combinedPrivateKeys, combinedPublicKeys, nil @@ -119,7 +140,7 @@ func setupLocalNetwork(ctx context.Context, configPath string, nodeCount int) (b privateKeys, publicKeys, err = loadKeys(configPath, nodeCount) if err != nil { - panic("Can't generate node keys") + panic(fmt.Sprintf("error generating node keys: %v", err)) } bootstrapPublicKeys = publicKeys signers := make([]*gossip2.GossipNode, len(privateKeys)) @@ -203,7 +224,7 @@ var ( func defaultCfgPath() string { usr, err := user.Current() if err != nil { - log.Warn("Error finding user: %v", err) + log.Warn("error finding user: %v", err) } return filepath.Join(usr.HomeDir, ".tupelo/local_network") } From 9a35b71db61d64c20756ba0d97dfe2dd83350dd1 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 14 Dec 2018 17:28:39 -0500 Subject: [PATCH 05/14] store session state in a configurable storage path --- cmd/rpcserver.go | 42 +++++++++++++++---------------- cmd/shell.go | 6 ++--- cmd/testnode.go | 20 ++++++++++++--- wallet/walletrpc/server.go | 38 +++++++++++++++------------- wallet/walletrpc/session.go | 8 +++--- wallet/walletshell/gossipshell.go | 4 +-- 6 files changed, 66 insertions(+), 52 deletions(-) diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index ad23b3ad..9453a39d 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -145,7 +145,7 @@ func setupLocalNetwork(ctx context.Context, configPath string, nodeCount int) (b bootstrapPublicKeys = publicKeys signers := make([]*gossip2.GossipNode, len(privateKeys)) for i, keys := range privateKeys { - signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, 0) + signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, configPath, 0) } // Use first signer as bootstrap node bootstrapAddrs = bootstrapAddresses(signers[0].Host) @@ -190,6 +190,22 @@ func panicWithoutTLSOpts() { } } +var ( + tls bool + certFile string + keyFile string + localNetworkNodeCount int + tupeloConfig string +) + +func defaultCfgPath() string { + usr, err := user.Current() + if err != nil { + log.Warn("error finding user: %v", err) + } + return filepath.Join(usr.HomeDir, ".tupelo/local_network") +} + var rpcServerCmd = &cobra.Command{ Use: "rpc-server", Short: "Launches a Tupelo RPC Server", @@ -199,42 +215,26 @@ var rpcServerCmd = &cobra.Command{ if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx, localConfigPath, localNetworkNodeCount) + bootstrapAddrs = setupLocalNetwork(ctx, tupeloConfig, localNetworkNodeCount) } notaryGroup := setupNotaryGroup(storage.NewMemStorage()) client := gossip2client.NewGossipClient(notaryGroup, bootstrapAddrs) if tls { panicWithoutTLSOpts() - walletrpc.ServeTLS(notaryGroup, client, certFile, keyFile) + walletrpc.ServeTLS(tupeloConfig, notaryGroup, client, certFile, keyFile) } else { - walletrpc.ServeInsecure(notaryGroup, client) + walletrpc.ServeInsecure(tupeloConfig, notaryGroup, client) } }, } -var ( - tls bool - certFile string - keyFile string - localNetworkNodeCount int - localConfigPath string -) - -func defaultCfgPath() string { - usr, err := user.Current() - if err != nil { - log.Warn("error finding user: %v", err) - } - return filepath.Join(usr.HomeDir, ".tupelo/local_network") -} - func init() { rootCmd.AddCommand(rpcServerCmd) rpcServerCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which public keys to bootstrap the notary groups with") rpcServerCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") rpcServerCmd.Flags().BoolVarP(&tls, "tls", "t", false, "Encrypt connections with TLS/SSL") - rpcServerCmd.Flags().StringVarP(&localConfigPath, "config-path", "c", defaultCfgPath(), "Local network configuration") + rpcServerCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") rpcServerCmd.Flags().StringVarP(&certFile, "tls-cert", "C", "", "TLS certificate file") rpcServerCmd.Flags().StringVarP(&keyFile, "tls-key", "K", "", "TLS private key file") } diff --git a/cmd/shell.go b/cmd/shell.go index 96fcaed4..0080514f 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -22,12 +22,12 @@ var shellCmd = &cobra.Command{ if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx, localConfigPath, localNetworkNodeCount) + bootstrapAddrs = setupLocalNetwork(ctx, tupeloConfig, localNetworkNodeCount) } group := setupNotaryGroup(storage.NewMemStorage()) client := gossip2client.NewGossipClient(group, bootstrapAddrs) - walletshell.RunGossip(shellName, group, client) + walletshell.RunGossip(shellName, tupeloConfig, group, client) }, } @@ -37,5 +37,5 @@ func init() { shellCmd.MarkFlagRequired("name") shellCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") shellCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") - shellCmd.Flags().StringVarP(&localConfigPath, "config-path", "c", defaultCfgPath(), "Local network configuration") + shellCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") } diff --git a/cmd/testnode.go b/cmd/testnode.go index 044f3dfb..9037d103 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -74,7 +74,7 @@ var testnodeCmd = &cobra.Command{ logging.SetLogLevel("gossip", "ERROR") ecdsaKeyHex := os.Getenv("NODE_ECDSA_KEY_HEX") blsKeyHex := os.Getenv("NODE_BLS_KEY_HEX") - signer := setupGossipNode(ctx, ecdsaKeyHex, blsKeyHex, testnodePort) + signer := setupGossipNode(ctx, ecdsaKeyHex, blsKeyHex, tupeloConfig, testnodePort) signer.Host.Bootstrap(p2p.BootstrapNodes()) go signer.Start() stopOnSignal(signer) @@ -93,7 +93,15 @@ func setupNotaryGroup(storageAdapter storage.Storage) *consensus.NotaryGroup { return group } -func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, port int) *gossip2.GossipNode { +func storagePath(parent string) string { + return filepath.Join(parent, "storage") +} + +func storageFile(path string, id string) string { + return filepath.Join(path, "testnode-chains-"+id) +} + +func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, configPath string, port int) *gossip2.GossipNode { ecdsaKey, err := crypto.ToECDSA(hexutil.MustDecode(ecdsaKeyHex)) if err != nil { panic("error fetching ecdsa key - set env variable NODE_ECDSA_KEY_HEX") @@ -104,8 +112,11 @@ func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, id := consensus.EcdsaToPublicKey(&ecdsaKey.PublicKey).Id log.Info("starting up a test node", "id", id) - os.MkdirAll(".storage", 0700) - badgerStorage, err := storage.NewBadgerStorage(filepath.Join(".storage", "testnode-chains-"+id)) + path := storagePath(configPath) + os.MkdirAll(path, 0700) + + file := storageFile(path, id) + badgerStorage, err := storage.NewBadgerStorage(file) if err != nil { panic(fmt.Sprintf("error creating storage: %v", err)) } @@ -143,4 +154,5 @@ func init() { rootCmd.AddCommand(testnodeCmd) testnodeCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") testnodeCmd.Flags().IntVarP(&testnodePort, "port", "p", 0, "what port will the node listen on") + testnodeCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") } diff --git a/wallet/walletrpc/server.go b/wallet/walletrpc/server.go index 6917fda6..08c3db28 100644 --- a/wallet/walletrpc/server.go +++ b/wallet/walletrpc/server.go @@ -22,10 +22,11 @@ const ( type server struct { NotaryGroup *consensus.NotaryGroup Client *gossip2client.GossipClient + storagePath string } func (s *server) Register(ctx context.Context, req *RegisterWalletRequest) (*RegisterWalletResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -42,7 +43,7 @@ func (s *server) Register(ctx context.Context, req *RegisterWalletRequest) (*Reg } func (s *server) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (*GenerateKeyResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -66,7 +67,7 @@ func (s *server) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (*Gen } func (s *server) ListKeys(ctx context.Context, req *ListKeysRequest) (*ListKeysResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -89,7 +90,7 @@ func (s *server) ListKeys(ctx context.Context, req *ListKeysRequest) (*ListKeysR } func (s *server) CreateChainTree(ctx context.Context, req *GenerateChainRequest) (*GenerateChainResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -117,7 +118,7 @@ func (s *server) CreateChainTree(ctx context.Context, req *GenerateChainRequest) } func (s *server) ExportChainTree(ctx context.Context, req *ExportChainRequest) (*ExportChainResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -140,7 +141,7 @@ func (s *server) ExportChainTree(ctx context.Context, req *ExportChainRequest) ( } func (s *server) ImportChainTree(ctx context.Context, req *ImportChainRequest) (*ImportChainResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -168,7 +169,7 @@ func (s *server) ImportChainTree(ctx context.Context, req *ImportChainRequest) ( } func (s *server) ListChainIds(ctx context.Context, req *ListChainIdsRequest) (*ListChainIdsResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -191,7 +192,7 @@ func (s *server) ListChainIds(ctx context.Context, req *ListChainIdsRequest) (*L } func (s *server) GetTip(ctx context.Context, req *GetTipRequest) (*GetTipResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -214,7 +215,7 @@ func (s *server) GetTip(ctx context.Context, req *GetTipRequest) (*GetTipRespons } func (s *server) SetOwner(ctx context.Context, req *SetOwnerRequest) (*SetOwnerResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -237,7 +238,7 @@ func (s *server) SetOwner(ctx context.Context, req *SetOwnerRequest) (*SetOwnerR } func (s *server) SetData(ctx context.Context, req *SetDataRequest) (*SetDataResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -260,7 +261,7 @@ func (s *server) SetData(ctx context.Context, req *SetDataRequest) (*SetDataResp } func (s *server) Resolve(ctx context.Context, req *ResolveRequest) (*ResolveResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -292,7 +293,7 @@ func (s *server) Resolve(ctx context.Context, req *ResolveRequest) (*ResolveResp } func (s *server) EstablishCoin(ctx context.Context, req *EstablishCoinRequest) (*EstablishCoinResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -315,7 +316,7 @@ func (s *server) EstablishCoin(ctx context.Context, req *EstablishCoinRequest) ( } func (s *server) MintCoin(ctx context.Context, req *MintCoinRequest) (*MintCoinResponse, error) { - session, err := NewSession(req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) if err != nil { return nil, err } @@ -337,7 +338,7 @@ func (s *server) MintCoin(ctx context.Context, req *MintCoinRequest) (*MintCoinR }, nil } -func startServer(grpcServer *grpc.Server, group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { +func startServer(grpcServer *grpc.Server, storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { fmt.Println("Starting Tupelo RPC server") fmt.Println("Listening on port", defaultPort) @@ -349,6 +350,7 @@ func startServer(grpcServer *grpc.Server, group *consensus.NotaryGroup, client * s := &server{ NotaryGroup: group, Client: client, + storagePath: storagePath, } RegisterWalletRPCServiceServer(grpcServer, s) @@ -361,13 +363,13 @@ func startServer(grpcServer *grpc.Server, group *consensus.NotaryGroup, client * return grpcServer, nil } -func ServeInsecure(group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { +func ServeInsecure(storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { grpcServer := grpc.NewServer() - return startServer(grpcServer, group, client) + return startServer(grpcServer, storagePath, group, client) } -func ServeTLS(group *consensus.NotaryGroup, client *gossip2client.GossipClient, certFile string, keyFile string) (*grpc.Server, error) { +func ServeTLS(storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient, certFile string, keyFile string) (*grpc.Server, error) { creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) if err != nil { return nil, err @@ -376,5 +378,5 @@ func ServeTLS(group *consensus.NotaryGroup, client *gossip2client.GossipClient, credsOption := grpc.Creds(creds) grpcServer := grpc.NewServer(credsOption) - return startServer(grpcServer, group, client) + return startServer(grpcServer, storagePath, group, client) } diff --git a/wallet/walletrpc/session.go b/wallet/walletrpc/session.go index 06cd0fd1..83fc5e0f 100644 --- a/wallet/walletrpc/session.go +++ b/wallet/walletrpc/session.go @@ -34,8 +34,8 @@ func (e ExistingChainError) Error() string { return fmt.Sprintf("A chain tree for public key %v has already been created.", keyAddr) } -func walletPath(name string) string { - return filepath.Join(".storage", name+"-wallet") +func walletPath(parent string, name string) string { + return filepath.Join(parent, name+"-wallet") } var StoppedError = errors.New("Unstarted wallet session") @@ -53,8 +53,8 @@ func (e *NilTipError) Error() string { return fmt.Sprintf("Chain tree with id %v is not known to the notary group %v", e.chainId, e.notaryGroup) } -func NewSession(walletName string, group *consensus.NotaryGroup, gossipClient *gossip2client.GossipClient) (*RPCSession, error) { - path := walletPath(walletName) +func NewSession(storagePath string, walletName string, group *consensus.NotaryGroup, gossipClient *gossip2client.GossipClient) (*RPCSession, error) { + path := walletPath(storagePath, walletName) fileWallet := wallet.NewFileWallet(path) diff --git a/wallet/walletshell/gossipshell.go b/wallet/walletshell/gossipshell.go index bdf6e73d..c1351c7d 100644 --- a/wallet/walletshell/gossipshell.go +++ b/wallet/walletshell/gossipshell.go @@ -33,7 +33,7 @@ func confirmPassword(c *ishell.Context) (string, error) { return "", errors.New("can't confirm password") } -func RunGossip(name string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) { +func RunGossip(name string, storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) { // by default, new shell includes 'exit', 'help' and 'clear' commands. shell := ishell.New() @@ -41,7 +41,7 @@ func RunGossip(name string, group *consensus.NotaryGroup, client *gossip2client. shell.Printf("Loading shell for wallet: %v\n", name) // load the session - session, err := walletrpc.NewSession(name, group, client) + session, err := walletrpc.NewSession(storagePath, name, group, client) if err != nil { shell.Printf("error loading shell: %v\n", err) return From 5185d8ab4579820fe955369132574149b3a5e351 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 17 Dec 2018 00:01:23 -0500 Subject: [PATCH 06/14] remove old .storage dir --- .storage/.gitkeep | 0 cmd/rpcserver.go | 15 ++++++++------- cmd/testnode.go | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 .storage/.gitkeep diff --git a/.storage/.gitkeep b/.storage/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index 9453a39d..1d0716c7 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -99,13 +99,13 @@ func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { return keySet, err } -func loadKeys(path string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { - privateKeys, err := loadPrivateKeyFile(path) +func loadKeys(networkPath string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { + privateKeys, err := loadPrivateKeyFile(networkPath) if err != nil { return nil, nil, fmt.Errorf("error loading private keys: %v", err) } - publicKeys, err := loadPublicKeyFile(path) + publicKeys, err := loadPublicKeyFile(networkPath) if err != nil { return nil, nil, fmt.Errorf("error loading public keys: %v", err) } @@ -120,7 +120,7 @@ func loadKeys(path string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { combinedPrivateKeys := append(privateKeys, extraPrivateKeys...) combinedPublicKeys := append(publicKeys, extraPublicKeys...) - err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, path) + err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, networkPath) if err != nil { return nil, nil, fmt.Errorf("error writing extra node keys: %v", err) } @@ -138,14 +138,15 @@ func setupLocalNetwork(ctx context.Context, configPath string, nodeCount int) (b var publicKeys []*PublicKeySet var privateKeys []*PrivateKeySet - privateKeys, publicKeys, err = loadKeys(configPath, nodeCount) + networkPath := filepath.Join(configPath, "local-network") + privateKeys, publicKeys, err = loadKeys(networkPath, nodeCount) if err != nil { panic(fmt.Sprintf("error generating node keys: %v", err)) } bootstrapPublicKeys = publicKeys signers := make([]*gossip2.GossipNode, len(privateKeys)) for i, keys := range privateKeys { - signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, configPath, 0) + signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, networkPath, 0) } // Use first signer as bootstrap node bootstrapAddrs = bootstrapAddresses(signers[0].Host) @@ -203,7 +204,7 @@ func defaultCfgPath() string { if err != nil { log.Warn("error finding user: %v", err) } - return filepath.Join(usr.HomeDir, ".tupelo/local_network") + return filepath.Join(usr.HomeDir, ".tupelo") } var rpcServerCmd = &cobra.Command{ diff --git a/cmd/testnode.go b/cmd/testnode.go index 9037d103..09d5c85a 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -98,7 +98,7 @@ func storagePath(parent string) string { } func storageFile(path string, id string) string { - return filepath.Join(path, "testnode-chains-"+id) + return filepath.Join(path, "node-chains-"+id) } func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, configPath string, port int) *gossip2.GossipNode { From ab1a6c5ea240fdbeddb649ce39982e2b2fe5510b Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 21 Dec 2018 00:17:16 -0500 Subject: [PATCH 07/14] remove unnecessary directory existence check. --- cmd/generateNodeKeys.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index 5c37c9da..bff8235d 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -66,11 +66,9 @@ func printTextKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet) { } func createDirIfNotExist(dir string) { - if _, err := os.Stat(dir); os.IsNotExist(err) { - err = os.MkdirAll(dir, 0700) - if err != nil { - panic(fmt.Sprintf("error creating directory: %v", err)) - } + err := os.MkdirAll(dir, 0700) + if err != nil { + panic(fmt.Sprintf("error creating directory: %v", err)) } } From 1720fabbff0d07dc36f0a6e74b30c8f7aab309a9 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 21 Dec 2018 03:32:55 -0500 Subject: [PATCH 08/14] remove config path option; platform dependent config paths --- cmd/generateNodeKeys.go | 35 ++++-------- cmd/root.go | 22 ++++++++ cmd/rpcserver.go | 114 ++++++++++------------------------------ cmd/shell.go | 6 +-- cmd/testnode.go | 21 +++----- 5 files changed, 67 insertions(+), 131 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index bff8235d..a1062e98 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -3,9 +3,6 @@ package cmd import ( "encoding/json" "fmt" - "io/ioutil" - "os" - "path/filepath" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" @@ -65,33 +62,20 @@ func printTextKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet) { } } -func createDirIfNotExist(dir string) { - err := os.MkdirAll(dir, 0700) - if err != nil { - panic(fmt.Sprintf("error creating directory: %v", err)) - } -} - -func privateKeyFile(configPath string) string { - return filepath.Join(configPath, "private-keys.json") -} - -func publicKeyFile(configPath string) string { - return filepath.Join(configPath, "public-keys.json") -} - -func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, path string) error { - createDirIfNotExist(path) +const ( + publicKeyFile = "public-keys.json" + privateKeyFile = "private-keys.json" +) +func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, namespace string) error { publicKeyJson, err := json.Marshal(publicKeys) if err != nil { return fmt.Errorf("Error marshaling public keys: %v", err) } - pubPath := publicKeyFile(path) - err = ioutil.WriteFile(pubPath, publicKeyJson, 0644) + err = writeConfig(namespace, publicKeyFile, publicKeyJson) if err != nil { - return fmt.Errorf("Error writing to path '%v': %v", pubPath, err) + return fmt.Errorf("error writing public keys: %v", err) } privateKeyJson, err := json.Marshal(privateKeys) @@ -99,10 +83,9 @@ func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, pat return fmt.Errorf("Error marshaling private keys: %v", err) } - prvPath := privateKeyFile(path) - err = ioutil.WriteFile(prvPath, privateKeyJson, 0644) + err = writeConfig(namespace, privateKeyFile, privateKeyJson) if err != nil { - return fmt.Errorf("Error writing to path '%v': %v", prvPath, err) + return fmt.Errorf("error writing private keys: %v", err) } return nil diff --git a/cmd/root.go b/cmd/root.go index c7a3c8fd..5cf61af1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/log" ipfslogging "github.com/ipsn/go-ipfs/gxlibs/github.com/ipfs/go-log" homedir "github.com/mitchellh/go-homedir" + "github.com/shibukawa/configdir" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -49,6 +50,27 @@ var cfgFile string var bootstrapPublicKeysFile string var bootstrapPublicKeys []*PublicKeySet +func configDir(namespace string) *configdir.Config { + conf := configdir.New("tupelo", namespace) + folders := conf.QueryFolders(configdir.Global) + + return folders[0] +} + +func readConfig(namespace string, name string) ([]byte, error) { + folder := configDir(namespace) + if !folder.Exists(name) { + return nil, nil + } + + return folder.ReadFile(name) +} + +func writeConfig(namespace string, name string, data []byte) error { + folder := configDir(namespace) + return folder.WriteFile(name, data) +} + type PublicKeySet struct { BlsHexPublicKey string `json:"blsHexPublicKey,omitempty"` EcdsaHexPublicKey string `json:"ecdsaHexPublicKey,omitempty"` diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index 1d0716c7..15897d66 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -4,14 +4,9 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" - "os" - "os/user" - "path/filepath" "strings" "time" - "github.com/ethereum/go-ethereum/log" "github.com/quorumcontrol/storage" "github.com/quorumcontrol/tupelo/gossip2" "github.com/quorumcontrol/tupelo/gossip2client" @@ -20,92 +15,49 @@ import ( "github.com/spf13/cobra" ) -func filePathExists(path string) bool { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - return false - } else { - panic(err) - } - } else { - return true - } -} - -func expandHomePath(path string) (string, error) { - currentUser, err := user.Current() - if err != nil { - return "", fmt.Errorf("error getting current user: %v", err) - } - homeDir := currentUser.HomeDir - - if path[:2] == "~/" { - path = filepath.Join(homeDir, path[2:]) - } - return path, nil -} - -func loadJSON(path string) ([]byte, error) { - if path == "" { - return nil, nil - } - modPath, err := expandHomePath(path) - if err != nil { - return nil, err - } - _, err = os.Stat(modPath) - if err != nil { - return nil, err - } +const localConfig = "local-network" - return ioutil.ReadFile(modPath) -} - -func loadKeyFile(keySet interface{}, path string) error { - jsonBytes, err := loadJSON(path) +func loadKeyFile(keySet interface{}, namespace string, name string) error { + jsonBytes, err := readConfig(namespace, name) if err != nil { - return err + return fmt.Errorf("error loading key file: %v", err) } - err = json.Unmarshal(jsonBytes, keySet) - if err != nil { - return err + if jsonBytes != nil { + err = json.Unmarshal(jsonBytes, keySet) + if err != nil { + return err + } } return nil } -func loadPublicKeyFile(path string) ([]*PublicKeySet, error) { +func loadPublicKeyFile(namespace string) ([]*PublicKeySet, error) { var keySet []*PublicKeySet var err error - pubPath := publicKeyFile(path) - if filePathExists(pubPath) { - err = loadKeyFile(&keySet, pubPath) - } + err = loadKeyFile(&keySet, namespace, publicKeyFile) return keySet, err } -func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { +func loadPrivateKeyFile(namespace string) ([]*PrivateKeySet, error) { var keySet []*PrivateKeySet var err error - prvPath := privateKeyFile(path) - if filePathExists(prvPath) { - err = loadKeyFile(&keySet, prvPath) - } + err = loadKeyFile(&keySet, namespace, privateKeyFile) return keySet, err } -func loadKeys(networkPath string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { - privateKeys, err := loadPrivateKeyFile(networkPath) +func loadKeys(network string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { + privateKeys, err := loadPrivateKeyFile(network) if err != nil { return nil, nil, fmt.Errorf("error loading private keys: %v", err) } - publicKeys, err := loadPublicKeyFile(networkPath) + publicKeys, err := loadPublicKeyFile(network) if err != nil { return nil, nil, fmt.Errorf("error loading public keys: %v", err) } @@ -120,7 +72,7 @@ func loadKeys(networkPath string, num int) ([]*PrivateKeySet, []*PublicKeySet, e combinedPrivateKeys := append(privateKeys, extraPrivateKeys...) combinedPublicKeys := append(publicKeys, extraPublicKeys...) - err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, networkPath) + err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, network) if err != nil { return nil, nil, fmt.Errorf("error writing extra node keys: %v", err) } @@ -133,27 +85,25 @@ func loadKeys(networkPath string, num int) ([]*PrivateKeySet, []*PublicKeySet, e } } -func setupLocalNetwork(ctx context.Context, configPath string, nodeCount int) (bootstrapAddrs []string) { - var err error - var publicKeys []*PublicKeySet - var privateKeys []*PrivateKeySet - - networkPath := filepath.Join(configPath, "local-network") - privateKeys, publicKeys, err = loadKeys(networkPath, nodeCount) +func setupLocalNetwork(ctx context.Context, nodeCount int) (bootstrapAddrs []string) { + privateKeys, publicKeys, err := loadKeys(localConfig, nodeCount) if err != nil { panic(fmt.Sprintf("error generating node keys: %v", err)) } + bootstrapPublicKeys = publicKeys signers := make([]*gossip2.GossipNode, len(privateKeys)) for i, keys := range privateKeys { - signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, networkPath, 0) + signers[i] = setupGossipNode(ctx, keys.EcdsaHexPrivateKey, keys.BlsHexPrivateKey, localConfig, 0) } + // Use first signer as bootstrap node bootstrapAddrs = bootstrapAddresses(signers[0].Host) // Have rest of signers bootstrap to node 0 for i := 1; i < len(signers); i++ { signers[i].Host.Bootstrap(bootstrapAddrs) } + // Give a chance for everything to bootstrap, then start time.Sleep(100 * time.Millisecond) for i := 0; i < len(signers); i++ { @@ -196,36 +146,27 @@ var ( certFile string keyFile string localNetworkNodeCount int - tupeloConfig string ) -func defaultCfgPath() string { - usr, err := user.Current() - if err != nil { - log.Warn("error finding user: %v", err) - } - return filepath.Join(usr.HomeDir, ".tupelo") -} - var rpcServerCmd = &cobra.Command{ Use: "rpc-server", Short: "Launches a Tupelo RPC Server", Run: func(cmd *cobra.Command, args []string) { - bootstrapAddrs := p2p.BootstrapNodes() if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx, tupeloConfig, localNetworkNodeCount) + bootstrapAddrs = setupLocalNetwork(ctx, localNetworkNodeCount) } + walletStorage := configDir("wallets").Path notaryGroup := setupNotaryGroup(storage.NewMemStorage()) client := gossip2client.NewGossipClient(notaryGroup, bootstrapAddrs) if tls { panicWithoutTLSOpts() - walletrpc.ServeTLS(tupeloConfig, notaryGroup, client, certFile, keyFile) + walletrpc.ServeTLS(walletStorage, notaryGroup, client, certFile, keyFile) } else { - walletrpc.ServeInsecure(tupeloConfig, notaryGroup, client) + walletrpc.ServeInsecure(walletStorage, notaryGroup, client) } }, } @@ -235,7 +176,6 @@ func init() { rpcServerCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which public keys to bootstrap the notary groups with") rpcServerCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") rpcServerCmd.Flags().BoolVarP(&tls, "tls", "t", false, "Encrypt connections with TLS/SSL") - rpcServerCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") rpcServerCmd.Flags().StringVarP(&certFile, "tls-cert", "C", "", "TLS certificate file") rpcServerCmd.Flags().StringVarP(&keyFile, "tls-key", "K", "", "TLS private key file") } diff --git a/cmd/shell.go b/cmd/shell.go index 0080514f..cc68075e 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -22,12 +22,13 @@ var shellCmd = &cobra.Command{ if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - bootstrapAddrs = setupLocalNetwork(ctx, tupeloConfig, localNetworkNodeCount) + bootstrapAddrs = setupLocalNetwork(ctx, localNetworkNodeCount) } + walletStorage := configDir("wallets").Path group := setupNotaryGroup(storage.NewMemStorage()) client := gossip2client.NewGossipClient(group, bootstrapAddrs) - walletshell.RunGossip(shellName, tupeloConfig, group, client) + walletshell.RunGossip(shellName, walletStorage, group, client) }, } @@ -37,5 +38,4 @@ func init() { shellCmd.MarkFlagRequired("name") shellCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") shellCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") - shellCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") } diff --git a/cmd/testnode.go b/cmd/testnode.go index 09d5c85a..3433500e 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -74,7 +74,7 @@ var testnodeCmd = &cobra.Command{ logging.SetLogLevel("gossip", "ERROR") ecdsaKeyHex := os.Getenv("NODE_ECDSA_KEY_HEX") blsKeyHex := os.Getenv("NODE_BLS_KEY_HEX") - signer := setupGossipNode(ctx, ecdsaKeyHex, blsKeyHex, tupeloConfig, testnodePort) + signer := setupGossipNode(ctx, ecdsaKeyHex, blsKeyHex, "distributed-network", testnodePort) signer.Host.Bootstrap(p2p.BootstrapNodes()) go signer.Start() stopOnSignal(signer) @@ -93,15 +93,7 @@ func setupNotaryGroup(storageAdapter storage.Storage) *consensus.NotaryGroup { return group } -func storagePath(parent string) string { - return filepath.Join(parent, "storage") -} - -func storageFile(path string, id string) string { - return filepath.Join(path, "node-chains-"+id) -} - -func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, configPath string, port int) *gossip2.GossipNode { +func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, namespace string, port int) *gossip2.GossipNode { ecdsaKey, err := crypto.ToECDSA(hexutil.MustDecode(ecdsaKeyHex)) if err != nil { panic("error fetching ecdsa key - set env variable NODE_ECDSA_KEY_HEX") @@ -112,11 +104,11 @@ func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, id := consensus.EcdsaToPublicKey(&ecdsaKey.PublicKey).Id log.Info("starting up a test node", "id", id) - path := storagePath(configPath) - os.MkdirAll(path, 0700) + storagePath := configDir(namespace).Path + os.MkdirAll(storagePath, 0700) - file := storageFile(path, id) - badgerStorage, err := storage.NewBadgerStorage(file) + db := filepath.Join(storagePath, id+"-chains") + badgerStorage, err := storage.NewBadgerStorage(db) if err != nil { panic(fmt.Sprintf("error creating storage: %v", err)) } @@ -154,5 +146,4 @@ func init() { rootCmd.AddCommand(testnodeCmd) testnodeCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") testnodeCmd.Flags().IntVarP(&testnodePort, "port", "p", 0, "what port will the node listen on") - testnodeCmd.Flags().StringVarP(&tupeloConfig, "config-path", "c", defaultCfgPath(), "Tupelo configuration") } From 8224688ab97d0d96c8367c1542cc2ba824986941 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sat, 29 Dec 2018 02:03:33 -0500 Subject: [PATCH 09/14] make bootstrapPublickeysfile a global command --- Gopkg.lock | 9 +++++++++ cmd/benchmark.go | 1 - cmd/root.go | 2 ++ cmd/rpcserver.go | 6 +++--- cmd/setloglevel.go | 1 - cmd/shell.go | 3 +-- cmd/testnode.go | 1 - cmd/workflowtest.go | 1 - 8 files changed, 15 insertions(+), 9 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 5447eeac..7fca05f4 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -804,6 +804,14 @@ pruneopts = "" revision = "49a4782e9908fe098c907022a1bd7519c79803d6" +[[projects]] + branch = "master" + digest = "1:adea3123626b97cc02423f77f21d6cd85c9461c3ad3221d62af604660c17a5a6" + name = "github.com/shibukawa/configdir" + packages = ["."] + pruneopts = "" + revision = "e180dbdc8da04c4fa04272e875ce64949f38bd3e" + [[projects]] digest = "1:633b5b39909d9d794f5543baee4971890e1866f5c082cdf4694954c1ff489a18" name = "github.com/spaolacci/murmur3" @@ -1169,6 +1177,7 @@ "github.com/quorumcontrol/chaintree/typecaster", "github.com/quorumcontrol/differencedigest/ibf", "github.com/quorumcontrol/storage", + "github.com/shibukawa/configdir", "github.com/spf13/cobra", "github.com/spf13/viper", "github.com/stretchr/testify/assert", diff --git a/cmd/benchmark.go b/cmd/benchmark.go index 0872a8d2..bf9a7d4b 100644 --- a/cmd/benchmark.go +++ b/cmd/benchmark.go @@ -282,7 +282,6 @@ var benchmark = &cobra.Command{ func init() { rootCmd.AddCommand(benchmark) - benchmark.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") benchmark.Flags().IntVarP(&benchmarkConcurrency, "concurrency", "c", 1, "how many transactions to execute at once") benchmark.Flags().IntVarP(&benchmarkIterations, "iterations", "i", 10, "how many transactions to execute total") benchmark.Flags().IntVarP(&benchmarkTimeout, "timeout", "t", 0, "seconds to wait before timing out") diff --git a/cmd/root.go b/cmd/root.go index 5cf61af1..bf5eda4a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -131,6 +131,8 @@ func init() { rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.PersistentFlags().StringVarP(&logLvlName, "log-level", "L", "error", "Log level") + rootCmd.PersistentFlags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") + } // initConfig reads in config file and ENV variables if set. diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index 15897d66..c26d15ea 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -142,10 +142,11 @@ func panicWithoutTLSOpts() { } var ( - tls bool certFile string - keyFile string localNetworkNodeCount int + keyFile string + remote bool + tls bool ) var rpcServerCmd = &cobra.Command{ @@ -173,7 +174,6 @@ var rpcServerCmd = &cobra.Command{ func init() { rootCmd.AddCommand(rpcServerCmd) - rpcServerCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which public keys to bootstrap the notary groups with") rpcServerCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") rpcServerCmd.Flags().BoolVarP(&tls, "tls", "t", false, "Encrypt connections with TLS/SSL") rpcServerCmd.Flags().StringVarP(&certFile, "tls-cert", "C", "", "TLS certificate file") diff --git a/cmd/setloglevel.go b/cmd/setloglevel.go index 4f66505e..65e2d6bd 100644 --- a/cmd/setloglevel.go +++ b/cmd/setloglevel.go @@ -41,5 +41,4 @@ var setloglevel = &cobra.Command{ func init() { rootCmd.AddCommand(setloglevel) - setloglevel.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") } diff --git a/cmd/shell.go b/cmd/shell.go index cc68075e..e523433b 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -16,7 +16,7 @@ var shellName string var shellCmd = &cobra.Command{ Use: "shell", Short: "Launch a Tupelo wallet shell connected to a local or remote signer network.", - Long: `Do not use this for anything real as it will use hard coded signing keys for the nodes`, + Long: ``, Run: func(cmd *cobra.Command, args []string) { var bootstrapAddrs []string = p2p.BootstrapNodes() if localNetworkNodeCount > 0 { @@ -36,6 +36,5 @@ func init() { rootCmd.AddCommand(shellCmd) shellCmd.Flags().StringVarP(&shellName, "name", "n", "", "the name to use for the wallet") shellCmd.MarkFlagRequired("name") - shellCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") shellCmd.Flags().IntVarP(&localNetworkNodeCount, "local-network", "l", 3, "Run local network with randomly generated keys, specifying number of nodes as argument. Mutually exlusive with bootstrap-*") } diff --git a/cmd/testnode.go b/cmd/testnode.go index 3433500e..c71d632e 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -144,6 +144,5 @@ func stopOnSignal(signers ...*gossip2.GossipNode) { func init() { rootCmd.AddCommand(testnodeCmd) - testnodeCmd.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") testnodeCmd.Flags().IntVarP(&testnodePort, "port", "p", 0, "what port will the node listen on") } diff --git a/cmd/workflowtest.go b/cmd/workflowtest.go index 77d71d5e..ed5ccd8e 100644 --- a/cmd/workflowtest.go +++ b/cmd/workflowtest.go @@ -88,5 +88,4 @@ var workflowtest = &cobra.Command{ func init() { rootCmd.AddCommand(workflowtest) - workflowtest.Flags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") } From 3c6e160a9c8645eae4f128ebe62a621e95855497 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Sun, 30 Dec 2018 23:51:35 -0500 Subject: [PATCH 10/14] rename bootstrapPublicKeysFile to overrideKeys --- cmd/root.go | 17 +++++++++-------- cmd/shell.go | 1 - 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index bf5eda4a..78da73c3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -45,10 +45,12 @@ func getLogLevel(lvlName string) (log.Lvl, error) { return lvl, nil } -var logLvlName string -var cfgFile string -var bootstrapPublicKeysFile string -var bootstrapPublicKeys []*PublicKeySet +var ( + bootstrapPublicKeys []*PublicKeySet + cfgFile string + logLvlName string + overrideKeysFile string +) func configDir(namespace string) *configdir.Config { conf := configdir.New("tupelo", namespace) @@ -88,9 +90,9 @@ var rootCmd = &cobra.Command{ Short: "Tupelo interface", Long: `Tupelo is a distributed ledger optimized for ownership`, PersistentPreRun: func(cmd *cobra.Command, args []string) { - if bootstrapPublicKeysFile != "" { + if overrideKeysFile != "" { var err error - bootstrapPublicKeys, err = loadPublicKeyFile(bootstrapPublicKeysFile) + bootstrapPublicKeys, err = loadPublicKeyFile(overrideKeysFile) if err != nil { panic(fmt.Sprintf("Error loading public keys: %v", err)) } @@ -131,8 +133,7 @@ func init() { rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.PersistentFlags().StringVarP(&logLvlName, "log-level", "L", "error", "Log level") - rootCmd.PersistentFlags().StringVarP(&bootstrapPublicKeysFile, "bootstrap-keys", "k", "", "which keys to bootstrap the notary groups with") - + rootCmd.PersistentFlags().StringVarP(&overrideKeysFile, "override-keys", "k", "", "which keys to bootstrap the notary groups with") } // initConfig reads in config file and ENV variables if set. diff --git a/cmd/shell.go b/cmd/shell.go index e523433b..ba3fb85e 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -16,7 +16,6 @@ var shellName string var shellCmd = &cobra.Command{ Use: "shell", Short: "Launch a Tupelo wallet shell connected to a local or remote signer network.", - Long: ``, Run: func(cmd *cobra.Command, args []string) { var bootstrapAddrs []string = p2p.BootstrapNodes() if localNetworkNodeCount > 0 { From a987ef0c119be00de437f986128fbffb999a9e2c Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Mon, 31 Dec 2018 00:57:45 -0500 Subject: [PATCH 11/14] remove redundant group argument passing --- cmd/rpcserver.go | 24 +++++++++++++------ cmd/shell.go | 13 +++++------ wallet/walletrpc/server.go | 39 ++++++++++++++----------------- wallet/walletrpc/session.go | 2 +- wallet/walletshell/gossipshell.go | 5 ++-- 5 files changed, 44 insertions(+), 39 deletions(-) diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index c26d15ea..be3e958c 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -141,10 +141,19 @@ func panicWithoutTLSOpts() { } } +func startClient(bootstrapAddrs []string) *gossip2client.GossipClient { + notaryGroup := setupNotaryGroup(storage.NewMemStorage()) + return gossip2client.NewGossipClient(notaryGroup, bootstrapAddrs) +} + +func walletPath() string { + return configDir("wallets").Path +} + var ( certFile string - localNetworkNodeCount int keyFile string + localNetworkNodeCount int remote bool tls bool ) @@ -153,21 +162,22 @@ var rpcServerCmd = &cobra.Command{ Use: "rpc-server", Short: "Launches a Tupelo RPC Server", Run: func(cmd *cobra.Command, args []string) { - bootstrapAddrs := p2p.BootstrapNodes() + var bootstrapAddrs []string if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() bootstrapAddrs = setupLocalNetwork(ctx, localNetworkNodeCount) + } else { + bootstrapAddrs = p2p.BootstrapNodes() } - walletStorage := configDir("wallets").Path - notaryGroup := setupNotaryGroup(storage.NewMemStorage()) - client := gossip2client.NewGossipClient(notaryGroup, bootstrapAddrs) + walletStorage := walletPath() + client := startClient(bootstrapAddrs) if tls { panicWithoutTLSOpts() - walletrpc.ServeTLS(walletStorage, notaryGroup, client, certFile, keyFile) + walletrpc.ServeTLS(walletStorage, client, certFile, keyFile) } else { - walletrpc.ServeInsecure(walletStorage, notaryGroup, client) + walletrpc.ServeInsecure(walletStorage, client) } }, } diff --git a/cmd/shell.go b/cmd/shell.go index ba3fb85e..4cbb3d53 100644 --- a/cmd/shell.go +++ b/cmd/shell.go @@ -3,8 +3,6 @@ package cmd import ( "context" - "github.com/quorumcontrol/storage" - "github.com/quorumcontrol/tupelo/gossip2client" "github.com/quorumcontrol/tupelo/p2p" "github.com/quorumcontrol/tupelo/wallet/walletshell" "github.com/spf13/cobra" @@ -17,17 +15,18 @@ var shellCmd = &cobra.Command{ Use: "shell", Short: "Launch a Tupelo wallet shell connected to a local or remote signer network.", Run: func(cmd *cobra.Command, args []string) { - var bootstrapAddrs []string = p2p.BootstrapNodes() + var bootstrapAddrs []string if localNetworkNodeCount > 0 { ctx, cancel := context.WithCancel(context.Background()) defer cancel() bootstrapAddrs = setupLocalNetwork(ctx, localNetworkNodeCount) + } else { + bootstrapAddrs = p2p.BootstrapNodes() } - walletStorage := configDir("wallets").Path - group := setupNotaryGroup(storage.NewMemStorage()) - client := gossip2client.NewGossipClient(group, bootstrapAddrs) - walletshell.RunGossip(shellName, walletStorage, group, client) + walletStorage := walletPath() + client := startClient(bootstrapAddrs) + walletshell.RunGossip(shellName, walletStorage, client) }, } diff --git a/wallet/walletrpc/server.go b/wallet/walletrpc/server.go index 08c3db28..6434f387 100644 --- a/wallet/walletrpc/server.go +++ b/wallet/walletrpc/server.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ipfs/go-ipld-cbor" - "github.com/quorumcontrol/tupelo/consensus" "github.com/quorumcontrol/tupelo/gossip2client" "golang.org/x/net/context" "google.golang.org/grpc" @@ -20,13 +19,12 @@ const ( ) type server struct { - NotaryGroup *consensus.NotaryGroup Client *gossip2client.GossipClient storagePath string } func (s *server) Register(ctx context.Context, req *RegisterWalletRequest) (*RegisterWalletResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -43,7 +41,7 @@ func (s *server) Register(ctx context.Context, req *RegisterWalletRequest) (*Reg } func (s *server) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (*GenerateKeyResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -67,7 +65,7 @@ func (s *server) GenerateKey(ctx context.Context, req *GenerateKeyRequest) (*Gen } func (s *server) ListKeys(ctx context.Context, req *ListKeysRequest) (*ListKeysResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -90,7 +88,7 @@ func (s *server) ListKeys(ctx context.Context, req *ListKeysRequest) (*ListKeysR } func (s *server) CreateChainTree(ctx context.Context, req *GenerateChainRequest) (*GenerateChainResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -118,7 +116,7 @@ func (s *server) CreateChainTree(ctx context.Context, req *GenerateChainRequest) } func (s *server) ExportChainTree(ctx context.Context, req *ExportChainRequest) (*ExportChainResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -141,7 +139,7 @@ func (s *server) ExportChainTree(ctx context.Context, req *ExportChainRequest) ( } func (s *server) ImportChainTree(ctx context.Context, req *ImportChainRequest) (*ImportChainResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -169,7 +167,7 @@ func (s *server) ImportChainTree(ctx context.Context, req *ImportChainRequest) ( } func (s *server) ListChainIds(ctx context.Context, req *ListChainIdsRequest) (*ListChainIdsResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -192,7 +190,7 @@ func (s *server) ListChainIds(ctx context.Context, req *ListChainIdsRequest) (*L } func (s *server) GetTip(ctx context.Context, req *GetTipRequest) (*GetTipResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -215,7 +213,7 @@ func (s *server) GetTip(ctx context.Context, req *GetTipRequest) (*GetTipRespons } func (s *server) SetOwner(ctx context.Context, req *SetOwnerRequest) (*SetOwnerResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -238,7 +236,7 @@ func (s *server) SetOwner(ctx context.Context, req *SetOwnerRequest) (*SetOwnerR } func (s *server) SetData(ctx context.Context, req *SetDataRequest) (*SetDataResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -261,7 +259,7 @@ func (s *server) SetData(ctx context.Context, req *SetDataRequest) (*SetDataResp } func (s *server) Resolve(ctx context.Context, req *ResolveRequest) (*ResolveResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -293,7 +291,7 @@ func (s *server) Resolve(ctx context.Context, req *ResolveRequest) (*ResolveResp } func (s *server) EstablishCoin(ctx context.Context, req *EstablishCoinRequest) (*EstablishCoinResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -316,7 +314,7 @@ func (s *server) EstablishCoin(ctx context.Context, req *EstablishCoinRequest) ( } func (s *server) MintCoin(ctx context.Context, req *MintCoinRequest) (*MintCoinResponse, error) { - session, err := NewSession(s.storagePath, req.Creds.WalletName, s.NotaryGroup, s.Client) + session, err := NewSession(s.storagePath, req.Creds.WalletName, s.Client) if err != nil { return nil, err } @@ -338,7 +336,7 @@ func (s *server) MintCoin(ctx context.Context, req *MintCoinRequest) (*MintCoinR }, nil } -func startServer(grpcServer *grpc.Server, storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { +func startServer(grpcServer *grpc.Server, storagePath string, client *gossip2client.GossipClient) (*grpc.Server, error) { fmt.Println("Starting Tupelo RPC server") fmt.Println("Listening on port", defaultPort) @@ -348,7 +346,6 @@ func startServer(grpcServer *grpc.Server, storagePath string, group *consensus.N } s := &server{ - NotaryGroup: group, Client: client, storagePath: storagePath, } @@ -363,13 +360,13 @@ func startServer(grpcServer *grpc.Server, storagePath string, group *consensus.N return grpcServer, nil } -func ServeInsecure(storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) (*grpc.Server, error) { +func ServeInsecure(storagePath string, client *gossip2client.GossipClient) (*grpc.Server, error) { grpcServer := grpc.NewServer() - return startServer(grpcServer, storagePath, group, client) + return startServer(grpcServer, storagePath, client) } -func ServeTLS(storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient, certFile string, keyFile string) (*grpc.Server, error) { +func ServeTLS(storagePath string, client *gossip2client.GossipClient, certFile string, keyFile string) (*grpc.Server, error) { creds, err := credentials.NewServerTLSFromFile(certFile, keyFile) if err != nil { return nil, err @@ -378,5 +375,5 @@ func ServeTLS(storagePath string, group *consensus.NotaryGroup, client *gossip2c credsOption := grpc.Creds(creds) grpcServer := grpc.NewServer(credsOption) - return startServer(grpcServer, storagePath, group, client) + return startServer(grpcServer, storagePath, client) } diff --git a/wallet/walletrpc/session.go b/wallet/walletrpc/session.go index 83fc5e0f..ba93368c 100644 --- a/wallet/walletrpc/session.go +++ b/wallet/walletrpc/session.go @@ -53,7 +53,7 @@ func (e *NilTipError) Error() string { return fmt.Sprintf("Chain tree with id %v is not known to the notary group %v", e.chainId, e.notaryGroup) } -func NewSession(storagePath string, walletName string, group *consensus.NotaryGroup, gossipClient *gossip2client.GossipClient) (*RPCSession, error) { +func NewSession(storagePath string, walletName string, gossipClient *gossip2client.GossipClient) (*RPCSession, error) { path := walletPath(storagePath, walletName) fileWallet := wallet.NewFileWallet(path) diff --git a/wallet/walletshell/gossipshell.go b/wallet/walletshell/gossipshell.go index c1351c7d..ea4dcf91 100644 --- a/wallet/walletshell/gossipshell.go +++ b/wallet/walletshell/gossipshell.go @@ -9,7 +9,6 @@ import ( "github.com/btcsuite/btcutil/base58" "github.com/ethereum/go-ethereum/crypto" "github.com/ipfs/go-ipld-cbor" - "github.com/quorumcontrol/tupelo/consensus" "github.com/quorumcontrol/tupelo/gossip2client" "github.com/quorumcontrol/tupelo/wallet/walletrpc" ) @@ -33,7 +32,7 @@ func confirmPassword(c *ishell.Context) (string, error) { return "", errors.New("can't confirm password") } -func RunGossip(name string, storagePath string, group *consensus.NotaryGroup, client *gossip2client.GossipClient) { +func RunGossip(name string, storagePath string, client *gossip2client.GossipClient) { // by default, new shell includes 'exit', 'help' and 'clear' commands. shell := ishell.New() @@ -41,7 +40,7 @@ func RunGossip(name string, storagePath string, group *consensus.NotaryGroup, cl shell.Printf("Loading shell for wallet: %v\n", name) // load the session - session, err := walletrpc.NewSession(storagePath, name, group, client) + session, err := walletrpc.NewSession(storagePath, name, client) if err != nil { shell.Printf("error loading shell: %v\n", err) return From e78fa888d00ab96db74903e3a852d9aa221049a0 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Wed, 2 Jan 2019 23:57:10 -0500 Subject: [PATCH 12/14] load and save local keys --- cmd/root.go | 85 ++++++++++++++++++++++++++++++++++++++++++------ cmd/rpcserver.go | 30 +++++++++-------- 2 files changed, 91 insertions(+), 24 deletions(-) diff --git a/cmd/root.go b/cmd/root.go index 78da73c3..72702e92 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -15,7 +15,9 @@ package cmd import ( + "encoding/json" "fmt" + "io/ioutil" "os" "strings" @@ -27,6 +29,20 @@ import ( "github.com/spf13/viper" ) +const ( + localConfig = "local-network" + remoteConfig = "remote-network" + bootstrapKeyFile = "bootstrap-keys.json" +) + +var ( + bootstrapPublicKeys []*PublicKeySet + cfgFile string + logLvlName string + newKeysFile string + overrideKeysFile string +) + var logLevels = map[string]log.Lvl{ "critical": log.LvlCrit, "error": log.LvlError, @@ -45,13 +61,6 @@ func getLogLevel(lvlName string) (log.Lvl, error) { return lvl, nil } -var ( - bootstrapPublicKeys []*PublicKeySet - cfgFile string - logLvlName string - overrideKeysFile string -) - func configDir(namespace string) *configdir.Config { conf := configdir.New("tupelo", namespace) folders := conf.QueryFolders(configdir.Global) @@ -73,6 +82,40 @@ func writeConfig(namespace string, name string, data []byte) error { return folder.WriteFile(name, data) } +func loadBootstrapKeyFile(path string) ([]*PublicKeySet, error) { + var keySet []*PublicKeySet + + file, err := ioutil.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("error reading path %v: %v", path, err) + } + + err = unmarshalKeys(keySet, file) + + return keySet, err +} + +func saveBootstrapKeys(keys []*PublicKeySet) error { + bootstrapKeyJson, err := json.Marshal(keys) + if err != nil { + return fmt.Errorf("Error marshaling bootstrap keys: %v", err) + } + + err = writeConfig(remoteConfig, bootstrapKeyFile, bootstrapKeyJson) + if err != nil { + return fmt.Errorf("error writing bootstrap keys: %v", err) + } + + return nil +} + +func readBootstrapKeys() ([]*PublicKeySet, error) { + var keySet []*PublicKeySet + err := loadKeyFile(keySet, remoteConfig, bootstrapKeyFile) + + return keySet, err +} + type PublicKeySet struct { BlsHexPublicKey string `json:"blsHexPublicKey,omitempty"` EcdsaHexPublicKey string `json:"ecdsaHexPublicKey,omitempty"` @@ -91,11 +134,19 @@ var rootCmd = &cobra.Command{ Long: `Tupelo is a distributed ledger optimized for ownership`, PersistentPreRun: func(cmd *cobra.Command, args []string) { if overrideKeysFile != "" { - var err error - bootstrapPublicKeys, err = loadPublicKeyFile(overrideKeysFile) + publicKeys, err := loadPublicKeyFile(overrideKeysFile) if err != nil { panic(fmt.Sprintf("Error loading public keys: %v", err)) } + + bootstrapPublicKeys = publicKeys + } else { + publicKeys, err := readBootstrapKeys() + if err != nil { + fmt.Printf("error loading stored bootstrap keys: %v", err) + } else { + bootstrapPublicKeys = publicKeys + } } logLevel, err := getLogLevel(logLvlName) @@ -105,10 +156,23 @@ var rootCmd = &cobra.Command{ log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(logLevel), log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) err = ipfslogging.SetLogLevel("*", strings.ToUpper(logLvlName)) if err != nil { - fmt.Println("unkown ipfs log level") + fmt.Println("unknown ipfs log level") } }, + Run: func(cmd *cobra.Command, args []string) { + if newKeysFile != "" { + keys, err := loadBootstrapKeyFile(newKeysFile) + if err != nil { + panic(fmt.Sprintf("Error loading bootstrap keys: %v", err)) + } + + err = saveBootstrapKeys(keys) + if err != nil { + panic(fmt.Sprintf("Error saving bootstrap keys: %v", err)) + } + } + }, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -134,6 +198,7 @@ func init() { rootCmd.PersistentFlags().StringVarP(&logLvlName, "log-level", "L", "error", "Log level") rootCmd.PersistentFlags().StringVarP(&overrideKeysFile, "override-keys", "k", "", "which keys to bootstrap the notary groups with") + rootCmd.Flags().StringVarP(&newKeysFile, "import-boot-keys", "i", "", "Path of key file to import") } // initConfig reads in config file and ENV variables if set. diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index be3e958c..264b2185 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -15,7 +15,16 @@ import ( "github.com/spf13/cobra" ) -const localConfig = "local-network" +func unmarshalKeys(keySet interface{}, bytes []byte) error { + if bytes != nil { + err := json.Unmarshal(bytes, keySet) + if err != nil { + return err + } + } + + return nil +} func loadKeyFile(keySet interface{}, namespace string, name string) error { jsonBytes, err := readConfig(namespace, name) @@ -23,14 +32,7 @@ func loadKeyFile(keySet interface{}, namespace string, name string) error { return fmt.Errorf("error loading key file: %v", err) } - if jsonBytes != nil { - err = json.Unmarshal(jsonBytes, keySet) - if err != nil { - return err - } - } - - return nil + return unmarshalKeys(keySet, jsonBytes) } func loadPublicKeyFile(namespace string) ([]*PublicKeySet, error) { @@ -51,13 +53,13 @@ func loadPrivateKeyFile(namespace string) ([]*PrivateKeySet, error) { return keySet, err } -func loadKeys(network string, num int) ([]*PrivateKeySet, []*PublicKeySet, error) { - privateKeys, err := loadPrivateKeyFile(network) +func loadLocalKeys(num int) ([]*PrivateKeySet, []*PublicKeySet, error) { + privateKeys, err := loadPrivateKeyFile(localConfig) if err != nil { return nil, nil, fmt.Errorf("error loading private keys: %v", err) } - publicKeys, err := loadPublicKeyFile(network) + publicKeys, err := loadPublicKeyFile(localConfig) if err != nil { return nil, nil, fmt.Errorf("error loading public keys: %v", err) } @@ -72,7 +74,7 @@ func loadKeys(network string, num int) ([]*PrivateKeySet, []*PublicKeySet, error combinedPrivateKeys := append(privateKeys, extraPrivateKeys...) combinedPublicKeys := append(publicKeys, extraPublicKeys...) - err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, network) + err = writeJSONKeys(combinedPrivateKeys, combinedPublicKeys, localConfig) if err != nil { return nil, nil, fmt.Errorf("error writing extra node keys: %v", err) } @@ -86,7 +88,7 @@ func loadKeys(network string, num int) ([]*PrivateKeySet, []*PublicKeySet, error } func setupLocalNetwork(ctx context.Context, nodeCount int) (bootstrapAddrs []string) { - privateKeys, publicKeys, err := loadKeys(localConfig, nodeCount) + privateKeys, publicKeys, err := loadLocalKeys(nodeCount) if err != nil { panic(fmt.Sprintf("error generating node keys: %v", err)) } From a64e58c734f7123c4d894eb7b0ea618a97367cac Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Thu, 3 Jan 2019 19:44:14 -0500 Subject: [PATCH 13/14] remove unnecessary example cobra flags; improve import doc string --- cmd/generateNodeKeys.go | 10 ---------- cmd/root.go | 11 +---------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index a1062e98..aaaebbd1 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -121,14 +121,4 @@ func init() { generateNodeKeysCmd.Flags().IntVarP(&generateNodeKeysCount, "count", "c", 1, "how many keys to generate") generateNodeKeysCmd.Flags().StringVarP(&generateNodeKeysOutput, "output", "o", "text", "format for keys output (default text): text, json-file") generateNodeKeysCmd.Flags().StringVarP(&generateNodeKeysPath, "path", "p", ".", "directory to store files if using json") - - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // generateNodeKeysCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // generateNodeKeysCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") } diff --git a/cmd/root.go b/cmd/root.go index 72702e92..906a5c82 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -187,18 +187,9 @@ func Execute() { func init() { cobra.OnInitialize(initConfig) - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.tupelo.yaml)") - - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - rootCmd.PersistentFlags().StringVarP(&logLvlName, "log-level", "L", "error", "Log level") rootCmd.PersistentFlags().StringVarP(&overrideKeysFile, "override-keys", "k", "", "which keys to bootstrap the notary groups with") - rootCmd.Flags().StringVarP(&newKeysFile, "import-boot-keys", "i", "", "Path of key file to import") + rootCmd.Flags().StringVarP(&newKeysFile, "import-boot-keys", "i", "", "Path of a notary group key file to import") } // initConfig reads in config file and ENV variables if set. From c8fc1d9fcaa7f63a14c0d96263dff74fdfb5e0b3 Mon Sep 17 00:00:00 2001 From: ben lamothe Date: Fri, 4 Jan 2019 03:06:26 -0500 Subject: [PATCH 14/14] Switch to absolute paths to allow for flexibility when saving config --- cmd/generateNodeKeys.go | 6 +++--- cmd/root.go | 32 +++++++++++++++++++------------- cmd/rpcserver.go | 14 +++++++------- cmd/testnode.go | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/cmd/generateNodeKeys.go b/cmd/generateNodeKeys.go index aaaebbd1..00636684 100644 --- a/cmd/generateNodeKeys.go +++ b/cmd/generateNodeKeys.go @@ -67,13 +67,13 @@ const ( privateKeyFile = "private-keys.json" ) -func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, namespace string) error { +func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, path string) error { publicKeyJson, err := json.Marshal(publicKeys) if err != nil { return fmt.Errorf("Error marshaling public keys: %v", err) } - err = writeConfig(namespace, publicKeyFile, publicKeyJson) + err = writeFile(path, publicKeyFile, publicKeyJson) if err != nil { return fmt.Errorf("error writing public keys: %v", err) } @@ -83,7 +83,7 @@ func writeJSONKeys(privateKeys []*PrivateKeySet, publicKeys []*PublicKeySet, nam return fmt.Errorf("Error marshaling private keys: %v", err) } - err = writeConfig(namespace, privateKeyFile, privateKeyJson) + err = writeFile(path, privateKeyFile, privateKeyJson) if err != nil { return fmt.Errorf("error writing private keys: %v", err) } diff --git a/cmd/root.go b/cmd/root.go index 906a5c82..25c1dc13 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -19,6 +19,7 @@ import ( "fmt" "io/ioutil" "os" + "path/filepath" "strings" "github.com/ethereum/go-ethereum/log" @@ -30,8 +31,6 @@ import ( ) const ( - localConfig = "local-network" - remoteConfig = "remote-network" bootstrapKeyFile = "bootstrap-keys.json" ) @@ -41,6 +40,9 @@ var ( logLvlName string newKeysFile string overrideKeysFile string + + localConfig = configDir("local-network") + remoteConfig = configDir("remote-network") ) var logLevels = map[string]log.Lvl{ @@ -61,25 +63,29 @@ func getLogLevel(lvlName string) (log.Lvl, error) { return lvl, nil } -func configDir(namespace string) *configdir.Config { +func configDir(namespace string) string { conf := configdir.New("tupelo", namespace) folders := conf.QueryFolders(configdir.Global) - return folders[0] + return folders[0].Path } -func readConfig(namespace string, name string) ([]byte, error) { - folder := configDir(namespace) - if !folder.Exists(name) { +func readConfig(path string, filename string) ([]byte, error) { + _, err := os.Stat(filepath.Join(path, filename)) + if os.IsNotExist(err) { return nil, nil } - return folder.ReadFile(name) + return ioutil.ReadFile(filepath.Join(path, filename)) } -func writeConfig(namespace string, name string, data []byte) error { - folder := configDir(namespace) - return folder.WriteFile(name, data) +func writeFile(parentDir string, filename string, data []byte) error { + err := os.MkdirAll(parentDir, 0755) + if err != nil { + return fmt.Errorf("error creating directory: %v", err) + } + + return ioutil.WriteFile(filepath.Join(parentDir, filename), data, 0644) } func loadBootstrapKeyFile(path string) ([]*PublicKeySet, error) { @@ -101,7 +107,7 @@ func saveBootstrapKeys(keys []*PublicKeySet) error { return fmt.Errorf("Error marshaling bootstrap keys: %v", err) } - err = writeConfig(remoteConfig, bootstrapKeyFile, bootstrapKeyJson) + err = writeFile(remoteConfig, bootstrapKeyFile, bootstrapKeyJson) if err != nil { return fmt.Errorf("error writing bootstrap keys: %v", err) } @@ -188,7 +194,7 @@ func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVarP(&logLvlName, "log-level", "L", "error", "Log level") - rootCmd.PersistentFlags().StringVarP(&overrideKeysFile, "override-keys", "k", "", "which keys to bootstrap the notary groups with") + rootCmd.PersistentFlags().StringVarP(&overrideKeysFile, "override-keys", "k", "", "path to notary group bootstrap keys file") rootCmd.Flags().StringVarP(&newKeysFile, "import-boot-keys", "i", "", "Path of a notary group key file to import") } diff --git a/cmd/rpcserver.go b/cmd/rpcserver.go index 264b2185..b631eca4 100644 --- a/cmd/rpcserver.go +++ b/cmd/rpcserver.go @@ -26,8 +26,8 @@ func unmarshalKeys(keySet interface{}, bytes []byte) error { return nil } -func loadKeyFile(keySet interface{}, namespace string, name string) error { - jsonBytes, err := readConfig(namespace, name) +func loadKeyFile(keySet interface{}, path string, name string) error { + jsonBytes, err := readConfig(path, name) if err != nil { return fmt.Errorf("error loading key file: %v", err) } @@ -35,20 +35,20 @@ func loadKeyFile(keySet interface{}, namespace string, name string) error { return unmarshalKeys(keySet, jsonBytes) } -func loadPublicKeyFile(namespace string) ([]*PublicKeySet, error) { +func loadPublicKeyFile(path string) ([]*PublicKeySet, error) { var keySet []*PublicKeySet var err error - err = loadKeyFile(&keySet, namespace, publicKeyFile) + err = loadKeyFile(&keySet, path, publicKeyFile) return keySet, err } -func loadPrivateKeyFile(namespace string) ([]*PrivateKeySet, error) { +func loadPrivateKeyFile(path string) ([]*PrivateKeySet, error) { var keySet []*PrivateKeySet var err error - err = loadKeyFile(&keySet, namespace, privateKeyFile) + err = loadKeyFile(&keySet, path, privateKeyFile) return keySet, err } @@ -149,7 +149,7 @@ func startClient(bootstrapAddrs []string) *gossip2client.GossipClient { } func walletPath() string { - return configDir("wallets").Path + return configDir("wallets") } var ( diff --git a/cmd/testnode.go b/cmd/testnode.go index c71d632e..18452dfe 100644 --- a/cmd/testnode.go +++ b/cmd/testnode.go @@ -104,7 +104,7 @@ func setupGossipNode(ctx context.Context, ecdsaKeyHex string, blsKeyHex string, id := consensus.EcdsaToPublicKey(&ecdsaKey.PublicKey).Id log.Info("starting up a test node", "id", id) - storagePath := configDir(namespace).Path + storagePath := configDir(namespace) os.MkdirAll(storagePath, 0700) db := filepath.Join(storagePath, id+"-chains")