mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-16 08:53:46 +00:00
Add account commands
This commit is contained in:
parent
8fe5c5a329
commit
74d384b6a4
8 changed files with 316 additions and 2 deletions
32
command/account.go
Normal file
32
command/account.go
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/mitchellh/cli"
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
UI cli.Ui
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (a *Account) Help() string {
|
||||||
|
return `Usage: bor account <subcommand>
|
||||||
|
|
||||||
|
This command groups actions to interact with accounts.
|
||||||
|
|
||||||
|
List the running deployments:
|
||||||
|
|
||||||
|
$ bor account new
|
||||||
|
|
||||||
|
Display the status of a specific deployment:
|
||||||
|
|
||||||
|
$ bor account import`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (a *Account) Synopsis() string {
|
||||||
|
return "Interact with accounts"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (a *Account) Run(args []string) int {
|
||||||
|
return cli.RunResultHelp
|
||||||
|
}
|
||||||
74
command/account_import.go
Normal file
74
command/account_import.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/command/flagset"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountImportCommand struct {
|
||||||
|
*Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (a *AccountImportCommand) Help() string {
|
||||||
|
return `Usage: bor account import
|
||||||
|
|
||||||
|
Import a private key into a new account.
|
||||||
|
|
||||||
|
Import an account:
|
||||||
|
|
||||||
|
$ bor account import key.json
|
||||||
|
|
||||||
|
` + a.Flags().Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccountImportCommand) Flags() *flagset.Flagset {
|
||||||
|
return a.NewFlagSet("account import")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (a *AccountImportCommand) Synopsis() string {
|
||||||
|
return "Import a private key into a new account"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (a *AccountImportCommand) Run(args []string) int {
|
||||||
|
flags := a.Flags()
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
a.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
args = flags.Args()
|
||||||
|
if len(args) != 1 {
|
||||||
|
a.UI.Error("Expected one argument")
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
key, err := crypto.LoadECDSA(args[0])
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(fmt.Sprintf("Failed to load the private key '%s': %v", args[0], err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
keystore, err := a.GetKeystore()
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := a.AskPassword()
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
acct, err := keystore.ImportECDSA(key, password)
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf("Could not create the account: %v", err)
|
||||||
|
}
|
||||||
|
a.UI.Output(fmt.Sprintf("Account created: %s", acct.Address.String()))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
62
command/account_list.go
Normal file
62
command/account_list.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/command/flagset"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountListCommand struct {
|
||||||
|
*Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (a *AccountListCommand) Help() string {
|
||||||
|
return `Usage: bor account list
|
||||||
|
|
||||||
|
List the local accounts.
|
||||||
|
|
||||||
|
` + a.Flags().Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccountListCommand) Flags() *flagset.Flagset {
|
||||||
|
return a.NewFlagSet("account list")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (a *AccountListCommand) Synopsis() string {
|
||||||
|
return "List the local accounts"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (a *AccountListCommand) Run(args []string) int {
|
||||||
|
flags := a.Flags()
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
a.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
keystore, err := a.GetKeystore()
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
a.UI.Output(formatAccounts(keystore.Accounts()))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatAccounts(accts []accounts.Account) string {
|
||||||
|
if len(accts) == 0 {
|
||||||
|
return "No accounts found"
|
||||||
|
}
|
||||||
|
|
||||||
|
rows := make([]string, len(accts)+1)
|
||||||
|
rows[0] = "Index|Address"
|
||||||
|
for i, d := range accts {
|
||||||
|
rows[i+1] = fmt.Sprintf("%d|%s",
|
||||||
|
i,
|
||||||
|
d.Address.String())
|
||||||
|
}
|
||||||
|
return formatList(rows)
|
||||||
|
}
|
||||||
62
command/account_new.go
Normal file
62
command/account_new.go
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/command/flagset"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountNewCommand struct {
|
||||||
|
*Meta
|
||||||
|
}
|
||||||
|
|
||||||
|
// Help implements the cli.Command interface
|
||||||
|
func (a *AccountNewCommand) Help() string {
|
||||||
|
return `Usage: bor account new
|
||||||
|
|
||||||
|
Create a new local account.
|
||||||
|
|
||||||
|
` + a.Flags().Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AccountNewCommand) Flags() *flagset.Flagset {
|
||||||
|
return a.NewFlagSet("account new")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synopsis implements the cli.Command interface
|
||||||
|
func (a *AccountNewCommand) Synopsis() string {
|
||||||
|
return "Create a new local account"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run implements the cli.Command interface
|
||||||
|
func (a *AccountNewCommand) Run(args []string) int {
|
||||||
|
flags := a.Flags()
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
a.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
keystore, err := a.GetKeystore()
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(fmt.Sprintf("Failed to get keystore: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
password, err := a.AskPassword()
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
account, err := keystore.NewAccount(password)
|
||||||
|
if err != nil {
|
||||||
|
a.UI.Error(fmt.Sprintf("Failed to create new account: %v", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
a.UI.Output("\nYour new key was generated")
|
||||||
|
a.UI.Output(fmt.Sprintf("Public address of the key: %s", account.Address.Hex()))
|
||||||
|
a.UI.Output(fmt.Sprintf("Path of the secret key file: %s", account.URL.Path))
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/command/flagset"
|
||||||
"github.com/ethereum/go-ethereum/command/server"
|
"github.com/ethereum/go-ethereum/command/server"
|
||||||
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
|
"github.com/ryanuber/columnize"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -35,6 +39,10 @@ func commands() map[string]cli.CommandFactory {
|
||||||
Writer: os.Stdout,
|
Writer: os.Stdout,
|
||||||
ErrorWriter: os.Stderr,
|
ErrorWriter: os.Stderr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta := &Meta{
|
||||||
|
UI: ui,
|
||||||
|
}
|
||||||
return map[string]cli.CommandFactory{
|
return map[string]cli.CommandFactory{
|
||||||
"server": func() (cli.Command, error) {
|
"server": func() (cli.Command, error) {
|
||||||
return &server.Command{
|
return &server.Command{
|
||||||
|
|
@ -46,5 +54,78 @@ func commands() map[string]cli.CommandFactory {
|
||||||
UI: ui,
|
UI: ui,
|
||||||
}, nil
|
}, nil
|
||||||
},
|
},
|
||||||
|
"account": func() (cli.Command, error) {
|
||||||
|
return &Account{
|
||||||
|
UI: ui,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"account new": func() (cli.Command, error) {
|
||||||
|
return &AccountNewCommand{
|
||||||
|
Meta: meta,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"account import": func() (cli.Command, error) {
|
||||||
|
return &AccountImportCommand{
|
||||||
|
Meta: meta,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
|
"account list": func() (cli.Command, error) {
|
||||||
|
return &AccountListCommand{
|
||||||
|
Meta: meta,
|
||||||
|
}, nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Meta is a helper utility for the commands
|
||||||
|
type Meta struct {
|
||||||
|
UI cli.Ui
|
||||||
|
|
||||||
|
dataDir string
|
||||||
|
keyStoreDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Meta) NewFlagSet(n string) *flagset.Flagset {
|
||||||
|
f := flagset.NewFlagSet(n)
|
||||||
|
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "datadir",
|
||||||
|
Value: &m.dataDir,
|
||||||
|
Usage: "Path of the data directory to store information",
|
||||||
|
})
|
||||||
|
f.StringFlag(&flagset.StringFlag{
|
||||||
|
Name: "keystore",
|
||||||
|
Value: &m.keyStoreDir,
|
||||||
|
Usage: "Path of the data directory to store information",
|
||||||
|
})
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Meta) AskPassword() (string, error) {
|
||||||
|
return m.UI.AskSecret("Your new account is locked with a password. Please give a password. Do not forget this password")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
|
||||||
|
cfg := node.DefaultConfig
|
||||||
|
cfg.DataDir = m.dataDir
|
||||||
|
cfg.KeyStoreDir = m.keyStoreDir
|
||||||
|
|
||||||
|
stack, err := node.New(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
keydir := stack.KeyStoreDir()
|
||||||
|
scryptN := keystore.StandardScryptN
|
||||||
|
scryptP := keystore.StandardScryptP
|
||||||
|
|
||||||
|
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
|
||||||
|
return keys, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatList(in []string) string {
|
||||||
|
columnConf := columnize.DefaultConfig()
|
||||||
|
columnConf.Empty = "<none>"
|
||||||
|
return columnize.Format(in, columnConf)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ type VersionCommand struct {
|
||||||
|
|
||||||
// Help implements the cli.Command interface
|
// Help implements the cli.Command interface
|
||||||
func (c *VersionCommand) Help() string {
|
func (c *VersionCommand) Help() string {
|
||||||
return `Usage: ensemble version
|
return `Usage: bor version
|
||||||
|
|
||||||
Display the Ensemble version`
|
Display the Bor version`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synopsis implements the cli.Command interface
|
// Synopsis implements the cli.Command interface
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -58,6 +58,7 @@ require (
|
||||||
github.com/prometheus/tsdb v0.7.1
|
github.com/prometheus/tsdb v0.7.1
|
||||||
github.com/rjeczalik/notify v0.9.1
|
github.com/rjeczalik/notify v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
|
github.com/ryanuber/columnize v2.1.2+incompatible
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
|
||||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -393,6 +393,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
|
||||||
|
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue