mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 18:02:24 +00:00
cmd/signer: minor changes
This commit is contained in:
parent
f88559e09f
commit
39d43a74b1
5 changed files with 57 additions and 56 deletions
|
|
@ -11,13 +11,23 @@ synchronised with the chain or a particular Ethereum node that has no build in,
|
||||||
|
|
||||||
In its current form the signer is very limited and designed to work with Mist. It hasn't got a connection to an
|
In its current form the signer is very limited and designed to work with Mist. It hasn't got a connection to an
|
||||||
Ethereum node. This restriction imposed many limitations such as the lack of ability to keep track of nonces, balances
|
Ethereum node. This restriction imposed many limitations such as the lack of ability to keep track of nonces, balances
|
||||||
or fetching additional information that can help the user to make a decision to sign a transaction or data. Currently
|
or fetching additional information that can help the user to make a decision to sign a transaction or data.
|
||||||
the signer only supports password protected accounts. Support for hardware tokens such as Trezor and Legder is planned.
|
|
||||||
|
|
||||||
## Command line flags
|
## Command line flags
|
||||||
The signer accepts the following command line options:
|
The signer accepts the following command line options:
|
||||||
- keystore, the directory where the password protected keystore stores keyfiles. The default directory is within geth's datadir. It is OS dependand, use `signer -h` to see where the location is on your system.
|
```
|
||||||
- chainid, the chain identifier. Default value is the Ethereum mainnet. See of a list of chain identifiers that are used https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md.
|
--chainid value chain identifier (default: 1)
|
||||||
|
--loglevel value log level to emit to the screen (default: 4)
|
||||||
|
--keystore value Directory for the keystore (default: "/home/martin/.ethereum/keystore")
|
||||||
|
--networkid value Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby) (default: 1)
|
||||||
|
--lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength
|
||||||
|
--nousb Disables monitoring for and managing USB hardware wallets
|
||||||
|
--rpcaddr value HTTP-RPC server listening interface (default: "localhost")
|
||||||
|
--rpcport value HTTP-RPC server listening port (default: 8550)
|
||||||
|
--4bytedb value File containing 4byte-identifiers (default: "./4byte.json")
|
||||||
|
--help, -h show help
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```
|
```
|
||||||
|
|
@ -25,7 +35,8 @@ signer -keystore /my/keystore -chainid 4
|
||||||
```
|
```
|
||||||
|
|
||||||
## Communicating
|
## Communicating
|
||||||
The signer listens on stdin for incoming requests and sends responses on stdout. Messages are expected to follow the
|
|
||||||
|
The signer listens to HTTP requests on `rpcaddr`:`rpcport`. The messages are expected to be JSON
|
||||||
[jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
|
[jsonrpc 2.0 standard](http://www.jsonrpc.org/specification).
|
||||||
|
|
||||||
Some of these call can require user interaction. Clients must be aware that responses may be deplayed significanlty or
|
Some of these call can require user interaction. Clients must be aware that responses may be deplayed significanlty or
|
||||||
|
|
@ -50,7 +61,8 @@ The client is responsible for creating a backup of the keystore. If the keystore
|
||||||
lost accounts.
|
lost accounts.
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
- passphrase [string]: passphrase that is used to protect the private key that is stored within the keystore
|
|
||||||
|
None
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
- address [string]: account address that is derived from the generated key
|
- address [string]: account address that is derived from the generated key
|
||||||
|
|
@ -83,7 +95,8 @@ lost accounts.
|
||||||
List all accounts that this signer currently manages
|
List all accounts that this signer currently manages
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
none
|
|
||||||
|
None
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
- array with account records:
|
- array with account records:
|
||||||
|
|
@ -120,11 +133,10 @@ lost accounts.
|
||||||
### account_signTransaction
|
### account_signTransaction
|
||||||
|
|
||||||
#### Sign transactions
|
#### Sign transactions
|
||||||
Signs a transactions and respons with the signed transaction in RLP encoded form.
|
Signs a transactions and responds with the signed transaction in RLP encoded form.
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
- from [address]: account to send the transaction from
|
- from [address]: account to send the transaction from
|
||||||
- passphrase [string]: passphrase to unlock the from account
|
|
||||||
- Transaction object:
|
- Transaction object:
|
||||||
- transaction.to [address]: receiver account
|
- transaction.to [address]: receiver account
|
||||||
- gas [number]: maximum amount of gas to burn
|
- gas [number]: maximum amount of gas to burn
|
||||||
|
|
@ -144,7 +156,6 @@ lost accounts.
|
||||||
"method": "account_signTransaction",
|
"method": "account_signTransaction",
|
||||||
"params": [
|
"params": [
|
||||||
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
||||||
"my password",
|
|
||||||
{
|
{
|
||||||
"gas": "0x55555",
|
"gas": "0x55555",
|
||||||
"gasPrice": "0x1234",
|
"gasPrice": "0x1234",
|
||||||
|
|
@ -170,7 +181,6 @@ lost accounts.
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
- account [address]: account to sign with
|
- account [address]: account to sign with
|
||||||
- passphrase [string]: passphrase to unlock the account
|
|
||||||
- data [data]: data to sign
|
- data [data]: data to sign
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
|
|
@ -184,7 +194,6 @@ lost accounts.
|
||||||
"method": "account_sign",
|
"method": "account_sign",
|
||||||
"params": [
|
"params": [
|
||||||
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
|
||||||
"my password",
|
|
||||||
"0xaabbccdd"
|
"0xaabbccdd"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -236,8 +245,6 @@ lost accounts.
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
- account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export)
|
- account [object]: key in [web3 keystore format](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) (retrieved with account_export)
|
||||||
- passphrase [string]: password to decrypt the given account
|
|
||||||
- newPassphrase [string]: password to encrypt the imported key in the keystore with
|
|
||||||
|
|
||||||
#### Result
|
#### Result
|
||||||
- imported key [object]:
|
- imported key [object]:
|
||||||
|
|
@ -273,8 +280,6 @@ lost accounts.
|
||||||
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
|
"id": "09bccb61-b8d3-4e93-bf4f-205a8194f0b9",
|
||||||
"version": 3
|
"version": 3
|
||||||
},
|
},
|
||||||
"my password",
|
|
||||||
"my password"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ type SignerAPI struct {
|
||||||
am *accounts.Manager
|
am *accounts.Manager
|
||||||
ui SignerUI
|
ui SignerUI
|
||||||
abidb abiDb
|
abidb abiDb
|
||||||
audit *auditlogger
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata about the request
|
// Metadata about the request
|
||||||
|
|
@ -173,7 +172,7 @@ func (ui *HeadlessUI) ShowInfo(message string) {
|
||||||
// key that is generated when a new account is created.
|
// key that is generated when a new account is created.
|
||||||
// noUSB disables USB support that is required to support hardware devices such as
|
// noUSB disables USB support that is required to support hardware devices such as
|
||||||
// ledger and trezor.
|
// ledger and trezor.
|
||||||
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb, auditlog string) *SignerAPI {
|
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb) *SignerAPI {
|
||||||
var backends []accounts.Backend
|
var backends []accounts.Backend
|
||||||
|
|
||||||
// support password based accounts
|
// support password based accounts
|
||||||
|
|
@ -197,11 +196,7 @@ func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abi
|
||||||
log.Debug("Trezor support enabled")
|
log.Debug("Trezor support enabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var al *auditlogger
|
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, *abidb}
|
||||||
if auditlog != ""{
|
|
||||||
al = &auditlogger{auditlog}
|
|
||||||
}
|
|
||||||
return &SignerAPI{big.NewInt(chainID), accounts.NewManager(backends...), ui, *abidb, al}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func metaData(ctx context.Context) Metadata {
|
func metaData(ctx context.Context) Metadata {
|
||||||
|
|
@ -300,6 +295,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address,
|
||||||
}
|
}
|
||||||
signedTx, err := wallet.SignTxWithPassphrase(acc, result.pw, tx, api.chainID)
|
signedTx, err := wallet.SignTxWithPassphrase(acc, result.pw, tx, api.chainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
api.ui.ShowError(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return rlp.EncodeToBytes(signedTx)
|
return rlp.EncodeToBytes(signedTx)
|
||||||
|
|
@ -337,6 +333,7 @@ func (api *SignerAPI) Sign(ctx context.Context, addr common.Address, data hexuti
|
||||||
// Assemble sign the data with the wallet
|
// Assemble sign the data with the wallet
|
||||||
signature, err := wallet.SignHashWithPassphrase(account, res.pw, sighash)
|
signature, err := wallet.SignHashWithPassphrase(account, res.pw, sighash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
api.ui.ShowError(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
||||||
|
|
@ -414,7 +411,8 @@ func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.Raw
|
||||||
// Imports tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
|
// Imports tries to import the given keyJSON in the local keystore. The keyJSON data is expected to be
|
||||||
// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful
|
// in web3 keystore format. It will decrypt the keyJSON with the given passphrase and on successful
|
||||||
// decryption it will encrypt the key with the given newPassphrase and store it in the keystore.
|
// decryption it will encrypt the key with the given newPassphrase and store it in the keystore.
|
||||||
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
|
func (api *SignerAPI) Import(ctx context.Context, string, keyJSON json.RawMessage) (Account, error) {
|
||||||
|
|
||||||
be := api.am.Backends(keystore.KeyStoreType)
|
be := api.am.Backends(keystore.KeyStoreType)
|
||||||
|
|
||||||
if len(be) == 0 {
|
if len(be) == 0 {
|
||||||
|
|
@ -424,10 +422,12 @@ func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Acco
|
||||||
ch := make(chan ImportResponse, 1)
|
ch := make(chan ImportResponse, 1)
|
||||||
|
|
||||||
api.ui.ApproveImport(&ImportRequest{}, metaData(ctx), ch)
|
api.ui.ApproveImport(&ImportRequest{}, metaData(ctx), ch)
|
||||||
|
|
||||||
if resp := <-ch; resp.approved {
|
if resp := <-ch; resp.approved {
|
||||||
|
|
||||||
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, resp.oldPassword, resp.newPassword)
|
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, resp.oldPassword, resp.newPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
api.ui.ShowError(err.Error())
|
||||||
return Account{}, err
|
return Account{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type auditlogger struct{
|
|
||||||
filename string
|
|
||||||
}
|
|
||||||
func (al auditlogger) append(text string) error{
|
|
||||||
f, err := os.OpenFile(al.filename, os.O_APPEND|os.O_WRONLY, 0600)
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("Failed to open audit log","err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if _, err = f.WriteString(text); err != nil {
|
|
||||||
log.Crit("Failed to write to audit log","err", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -54,21 +54,37 @@ func (ui *CommandlineUI) readString() string {
|
||||||
// readPassword reads a single line from stdin, trimming it from the trailing new
|
// readPassword reads a single line from stdin, trimming it from the trailing new
|
||||||
// line and returns it. The input will not be echoed.
|
// line and returns it. The input will not be echoed.
|
||||||
func (ui *CommandlineUI) readPassword() string {
|
func (ui *CommandlineUI) readPassword() string {
|
||||||
|
fmt.Printf("Enter password to approve:\n")
|
||||||
fmt.Printf("> ")
|
fmt.Printf("> ")
|
||||||
text, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
text, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Crit("Failed to read password", "err", err)
|
log.Crit("Failed to read password", "err", err)
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
fmt.Println("-----------------------")
|
||||||
|
return string(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readPassword reads a single line from stdin, trimming it from the trailing new
|
||||||
|
// line and returns it. The input will not be echoed.
|
||||||
|
func (ui *CommandlineUI) readPasswordText(inputstring string) string {
|
||||||
|
fmt.Printf("Enter %s:\n", inputstring)
|
||||||
|
fmt.Printf("> ")
|
||||||
|
text, err := terminal.ReadPassword(int(os.Stdin.Fd()))
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Failed to read password", "err", err)
|
||||||
|
}
|
||||||
|
fmt.Println("-----------------------")
|
||||||
return string(text)
|
return string(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// confirm returns true if user enters 'Yes', otherwise false
|
// confirm returns true if user enters 'Yes', otherwise false
|
||||||
func (ui *CommandlineUI) confirm() bool {
|
func (ui *CommandlineUI) confirm() bool {
|
||||||
fmt.Printf("Type 'Yes' to approve\n")
|
fmt.Printf("Type 'Yes' to approve:\n")
|
||||||
if ui.readString() == "Yes" {
|
if ui.readString() == "Yes" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
fmt.Println("-----------------------")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +114,7 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch
|
||||||
showMetadata(metadata)
|
showMetadata(metadata)
|
||||||
fmt.Printf("-------------------------------------------\n")
|
fmt.Printf("-------------------------------------------\n")
|
||||||
|
|
||||||
ch <- SignTxResponse{request.transaction.Hash(), ui.confirm(), ""}
|
ch <- SignTxResponse{request.transaction.Hash(), true ,ui.readPassword()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApproveSignData prompt the user for confirmation to request to sign data
|
// ApproveSignData prompt the user for confirmation to request to sign data
|
||||||
|
|
@ -113,7 +129,7 @@ func (ui *CommandlineUI) ApproveSignData(request *SignDataRequest, metadata Meta
|
||||||
fmt.Printf("message hash: %v\n", request.hash)
|
fmt.Printf("message hash: %v\n", request.hash)
|
||||||
fmt.Printf("-------------------------------------------\n")
|
fmt.Printf("-------------------------------------------\n")
|
||||||
showMetadata(metadata)
|
showMetadata(metadata)
|
||||||
ch <- SignDataResponse{ui.confirm(), ""}
|
ch <- SignDataResponse{true, ui.readPassword()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApproveExport prompt the user for confirmation to export encrypted account json
|
// ApproveExport prompt the user for confirmation to export encrypted account json
|
||||||
|
|
@ -141,7 +157,11 @@ func (ui *CommandlineUI) ApproveImport(request *ImportRequest, metadata Metadata
|
||||||
fmt.Printf("A request has been made to import an encrypted keyfile\n")
|
fmt.Printf("A request has been made to import an encrypted keyfile\n")
|
||||||
fmt.Printf("-------------------------------------------\n")
|
fmt.Printf("-------------------------------------------\n")
|
||||||
showMetadata(metadata)
|
showMetadata(metadata)
|
||||||
ch <- ImportResponse{ui.confirm(), "", ""}
|
if ui.confirm(){
|
||||||
|
ch <- ImportResponse{true, ui.readPasswordText("Old password"), ui.readPasswordText("New password")}
|
||||||
|
}else{
|
||||||
|
ch <- ImportResponse{false, "", ""}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApproveListing prompt the user for confirmation to list accounts
|
// ApproveListing prompt the user for confirmation to list accounts
|
||||||
|
|
@ -177,17 +197,17 @@ func (ui *CommandlineUI) ApproveNewAccount(requst *NewAccountRequest, metadata M
|
||||||
fmt.Printf("Approving this operation means that a new account is created,\n")
|
fmt.Printf("Approving this operation means that a new account is created,\n")
|
||||||
fmt.Printf("and the address show to the caller\n")
|
fmt.Printf("and the address show to the caller\n")
|
||||||
showMetadata(metadata)
|
showMetadata(metadata)
|
||||||
ch <- NewAccountResponse{ui.confirm(), ""}
|
ch <- NewAccountResponse{ui.confirm(), ui.readPassword()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowError displays error message to user
|
// ShowError displays error message to user
|
||||||
func (ui *CommandlineUI) ShowError(message string) {
|
func (ui *CommandlineUI) ShowError(message string) {
|
||||||
|
|
||||||
fmt.Printf("ERROR: %v", message)
|
fmt.Printf("ERROR: %v\n", message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowInfo displays info message to user
|
// ShowInfo displays info message to user
|
||||||
func (ui *CommandlineUI) ShowInfo(message string) {
|
func (ui *CommandlineUI) ShowInfo(message string) {
|
||||||
|
|
||||||
fmt.Printf("Info: %v", message)
|
fmt.Printf("Info: %v\n", message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,7 @@ func main() {
|
||||||
c.Int64(utils.NetworkIdFlag.Name),
|
c.Int64(utils.NetworkIdFlag.Name),
|
||||||
c.String("keystore"),
|
c.String("keystore"),
|
||||||
c.Bool(utils.NoUSBFlag.Name),
|
c.Bool(utils.NoUSBFlag.Name),
|
||||||
NewCommandlineUI(), db,
|
NewCommandlineUI(), db)
|
||||||
c.String("auditlog"))
|
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
//err error
|
//err error
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue