Skip to content

Commit

Permalink
Add ethkey functionality as alicenet built int CLI commands (#232)
Browse files Browse the repository at this point in the history
* adding generate-ethkey cmd to ./alicenet
* removing import from tools.go
  • Loading branch information
kosegor committed Sep 6, 2022
1 parent cb8ab6a commit f668c43
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 4 deletions.
135 changes: 135 additions & 0 deletions cmd/ethkey/ethkey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package ethkey

import (
"crypto/ecdsa"
"encoding/json"
"fmt"
"github.com/alicenet/alicenet/config"
"github.com/alicenet/alicenet/logging"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/crypto"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"os"
"path/filepath"
"strings"
)

const (
defaultKeyfileName = "keyfile.json"
)

type outputGenerate struct {
Address string
AddressEIP55 string
}

// Command is the cobra.Command specifically for generating an ethereum key and address.
var Command = cobra.Command{
Use: "generate-ethkey",
Short: "Generate a new keyfile",
Long: "Generate a new keyfile with an ethereum address and private key",
Run: generate,
}

func generate(cmd *cobra.Command, args []string) {
logger := logging.GetLogger("ethkey")

// Check if keyfile path given and make sure it doesn't already exist.
keyfilepath := defaultKeyfileName
if len(args) > 0 && args[0] != "" {
keyfilepath = args[0]
}
if _, err := os.Stat(keyfilepath); err == nil {
logger.Fatalf("Keyfile already exists at %s.", keyfilepath)
} else if !os.IsNotExist(err) {
logger.Fatalf("Error checking if keyfile exists: %v", err)
}

var privateKey *ecdsa.PrivateKey
var err error
if file := config.Configuration.EthKey.PrivateKey; file != "" {
// Load private key from file.
privateKey, err = crypto.LoadECDSA(file)
if err != nil {
logger.Fatalf("Can't load private key: %v", err)
}
} else {
// If not loaded, generate random.
privateKey, err = crypto.GenerateKey()
if err != nil {
logger.Fatalf("Failed to generate random private key: %v", err)
}
}

// Create the keyfile object with a random UUID.
UUID, err := uuid.NewRandom()
if err != nil {
logger.Fatalf("Failed to generate random uuid: %v", err)
}
key := &keystore.Key{
Id: UUID,
Address: crypto.PubkeyToAddress(privateKey.PublicKey),
PrivateKey: privateKey,
}

// Encrypt key with passphrase.
passphrase := getPassphrase(true, logger)
scryptN, scryptP := keystore.StandardScryptN, keystore.StandardScryptP
if config.Configuration.EthKey.LightKDF {
scryptN, scryptP = keystore.LightScryptN, keystore.LightScryptP
}
keyjson, err := keystore.EncryptKey(key, passphrase, scryptN, scryptP)
if err != nil {
logger.Fatalf("Error encrypting key: %v", err)
}

// Store the file to disk.
if err := os.MkdirAll(filepath.Dir(keyfilepath), 0700); err != nil {
logger.Fatalf("Could not create directory %s", filepath.Dir(keyfilepath))
}
if err := os.WriteFile(keyfilepath, keyjson, 0600); err != nil {
logger.Fatalf("Failed to write keyfile to %s: %v", keyfilepath, err)
}

// Output some information.
out := outputGenerate{
Address: key.Address.Hex(),
}
if config.Configuration.EthKey.Json {
mustPrintJSON(out, logger)
} else {
fmt.Println("Address:", out.Address)
}
}

// getPassphrase obtains a passphrase given by the user. It first checks the
// --passfile command line flag and ultimately prompts the user for a
// passphrase.
func getPassphrase(confirmation bool, logger *logrus.Logger) string {
// Look for the --passwordfile flag.
passphraseFile := config.Configuration.EthKey.PasswordFile
if passphraseFile != "" {
content, err := os.ReadFile(passphraseFile)
if err != nil {
logger.Fatalf("Failed to read password file '%s': %v",
passphraseFile, err)
}
return strings.TrimRight(string(content), "\r\n")
}

// Otherwise prompt the user for the passphrase.
return utils.GetPassPhrase("", confirmation)
}

// mustPrintJSON prints the JSON encoding of the given object and
// exits the program with an error message when the marshaling fails.
func mustPrintJSON(jsonObject interface{}, logger *logrus.Logger) {
str, err := json.MarshalIndent(jsonObject, "", " ")
if err != nil {
logger.Fatalf("Failed to marshal JSON object: %v", err)
}
fmt.Println(string(str))
}
9 changes: 9 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"bytes"
"github.com/alicenet/alicenet/cmd/ethkey"
"io/ioutil"
"os"
"reflect"
Expand Down Expand Up @@ -180,13 +181,21 @@ func main() {
{"validator.rewardAccount", "", "", &config.Configuration.Validator.RewardAccount},
{"validator.rewardCurveSpec", "", "", &config.Configuration.Validator.RewardCurveSpec},
},

&ethkey.Command: {
{"ethkey.passwordfile", "", "the file that contains the password for the keyfile", &config.Configuration.EthKey.PasswordFile},
{"ethkey.json", "", "output JSON instead of human-readable format", &config.Configuration.EthKey.Json},
{"ethkey.privatekey", "", "file containing a raw private key to encrypt", &config.Configuration.EthKey.PrivateKey},
{"ethkey.lightkdf", "", "use less secure scrypt parameters", &config.Configuration.EthKey.LightKDF},
},
}

// Establish command hierarchy
hierarchy := map[*cobra.Command]*cobra.Command{
&firewalld.Command: &rootCommand,
&bootnode.Command: &rootCommand,
&validator.Command: &rootCommand,
&ethkey.Command: &rootCommand,
&utils.Command: &rootCommand,
&utils.SendWeiCommand: &utils.Command,
}
Expand Down
8 changes: 8 additions & 0 deletions config/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ type firewalldConfig struct {
SocketFile string
}

type ethKeyConfig struct {
PasswordFile string
Json bool
PrivateKey string
LightKDF bool
}

type configuration struct {
ConfigurationFileName string
LoggingLevels string // backwards compatibility
Expand All @@ -118,6 +125,7 @@ type configuration struct {
Firewalld firewalldConfig
Chain chainConfig
BootNode bootnodeConfig
EthKey ethKeyConfig
Version string
}

Expand Down
1 change: 1 addition & 0 deletions constants/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,5 @@ var ValidLoggers []string = []string{
"transaction",
"tasks",
"staterecover",
"ethkey",
}
6 changes: 3 additions & 3 deletions scripts/main.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ CREATE_CONFIGS() {
CLEAN_UP
# Loop through and create all essentail validator files
for ((l = 1; l <= $1; l++)); do
ADDRESS=$(ethkey generate --passwordfile ./scripts/base-files/passwordFile | cut -d' ' -f2)
ADDRESS=$(./alicenet generate-ethkey --ethkey.passwordfile ./scripts/base-files/passwordFile | cut -d' ' -f2)
PK=$(hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/urandom)
sed -e 's/defaultAccount = .*/defaultAccount = \"'"$ADDRESS"'\"/' ./scripts/base-files/baseConfig |
sed -e 's/rewardAccount = .*/rewardAccount = \"'"$ADDRESS"'\"/' |
Expand Down Expand Up @@ -114,9 +114,9 @@ CREATE_EXTRA_NODES_CONFIGS() {
exit 1
fi
CLEAN_UP_NODES
# Loop through and create all essentail validator files
# Loop through and create all essential validator files
for ((l = 1; l <= $1; l++)); do
ADDRESS=$(ethkey generate --passwordfile ./scripts/base-files/passwordFile | cut -d' ' -f2)
ADDRESS=$(./alicenet generate-ethkey --ethkey.passwordfile ./scripts/base-files/passwordFile | cut -d' ' -f2)
PK=$(hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/urandom)
sed -e 's/defaultAccount = .*/defaultAccount = \"'"$ADDRESS"'\"/' ./scripts/base-files/baseConfig |
sed -e 's/rewardAccount = .*/rewardAccount = \"'"$ADDRESS"'\"/' |
Expand Down
1 change: 0 additions & 1 deletion tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
_ "github.com/bufbuild/buf/cmd/buf"
_ "github.com/derision-test/go-mockgen/cmd/go-mockgen"
_ "github.com/ethereum/go-ethereum/cmd/abigen"
_ "github.com/ethereum/go-ethereum/cmd/ethkey"
_ "github.com/ethereum/go-ethereum/cmd/geth"
_ "github.com/vburenin/ifacemaker"
_ "golang.org/x/tools/cmd/goimports"
Expand Down

0 comments on commit f668c43

Please sign in to comment.