mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-17 17:33:47 +00:00
cmd/signer: Made lowercase json-definitions, added UI-signer test functionality
This commit is contained in:
parent
d0c0b9bacd
commit
cd84631194
5 changed files with 187 additions and 61 deletions
|
|
@ -45,70 +45,73 @@ type SignerAPI struct {
|
|||
|
||||
// Metadata about the request
|
||||
type Metadata struct {
|
||||
remote string
|
||||
local string
|
||||
scheme string
|
||||
Remote string `json:"remote"`
|
||||
Local string `json:"local"`
|
||||
Scheme string `json:"scheme"`
|
||||
}
|
||||
|
||||
// types for the requests/response types
|
||||
type (
|
||||
// SignTxRequest contains info about a Transaction to sign
|
||||
SignTxRequest struct {
|
||||
Transaction TransactionArg
|
||||
From common.Address
|
||||
Callinfo fmt.Stringer
|
||||
Meta Metadata
|
||||
Transaction TransactionArg `json:"transaction"`
|
||||
From common.Address `json:"fromaccount"`
|
||||
Callinfo fmt.Stringer `json:"call_info"`
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
// SignTxResponse result from SignTxRequest
|
||||
SignTxResponse struct {
|
||||
//The UI may make changes to the TX
|
||||
Transaction TransactionArg
|
||||
From common.Address
|
||||
Approved bool
|
||||
Password string
|
||||
Approved bool `json:"approved"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
// ExportRequest info about query to export accounts
|
||||
ExportRequest struct {
|
||||
Address common.Address
|
||||
Meta Metadata
|
||||
Address common.Address `json:"address"`
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
// ExportResponse response to export-request
|
||||
ExportResponse struct {
|
||||
Approved bool
|
||||
Approved bool `json:"approved"`
|
||||
}
|
||||
// ImportRequest info about request to import an Account
|
||||
ImportRequest struct {
|
||||
Meta Metadata
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
ImportResponse struct {
|
||||
Approved bool
|
||||
OldPassword string
|
||||
NewPassword string
|
||||
Approved bool `json:"approved"`
|
||||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
SignDataRequest struct {
|
||||
Address common.Address
|
||||
Rawdata hexutil.Bytes
|
||||
Message string
|
||||
Hash hexutil.Bytes
|
||||
Meta Metadata
|
||||
Address common.Address `json:"address"`
|
||||
Rawdata hexutil.Bytes `json:"raw_data"`
|
||||
Message string `json:"message"`
|
||||
Hash hexutil.Bytes `json:"hash"`
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
SignDataResponse struct {
|
||||
Approved bool
|
||||
Approved bool `json:"approved"`
|
||||
Password string
|
||||
}
|
||||
NewAccountRequest struct {
|
||||
Meta Metadata
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
NewAccountResponse struct {
|
||||
Approved bool
|
||||
Password string
|
||||
Approved bool `json:"approved"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
ListRequest struct {
|
||||
Accounts []Account
|
||||
Meta Metadata
|
||||
Accounts []Account `json:"accounts"`
|
||||
Meta Metadata `json:"meta"`
|
||||
}
|
||||
ListResponse struct {
|
||||
Accounts []Account
|
||||
Accounts []Account `json:"accounts"`
|
||||
}
|
||||
Message struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -186,13 +189,13 @@ func metaData(ctx context.Context) Metadata {
|
|||
m := Metadata{"NA", "NA", "NA"}
|
||||
|
||||
if v := ctx.Value("remote"); v != nil {
|
||||
m.remote = v.(string)
|
||||
m.Remote = v.(string)
|
||||
}
|
||||
if v := ctx.Value("scheme"); v != nil {
|
||||
m.scheme = v.(string)
|
||||
m.Scheme = v.(string)
|
||||
}
|
||||
if v := ctx.Value("local"); v != nil {
|
||||
m.local = v.(string)
|
||||
m.Local = v.(string)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
|
@ -463,7 +466,7 @@ 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
|
||||
// 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.
|
||||
func (api *SignerAPI) Import(ctx context.Context, string, keyJSON json.RawMessage) (Account, error) {
|
||||
func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Account, error) {
|
||||
|
||||
be := api.am.Backends(keystore.KeyStoreType)
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ func (ui *CommandlineUI) confirm() bool {
|
|||
}
|
||||
|
||||
func showMetadata(metadata Metadata) {
|
||||
fmt.Printf("Request info:\n\t%v -> %v -> %v\n", metadata.remote, metadata.scheme, metadata.local)
|
||||
fmt.Printf("Request info:\n\t%v -> %v -> %v\n", metadata.Remote, metadata.Scheme, metadata.Local)
|
||||
}
|
||||
|
||||
// ApproveTx prompt the user for confirmation to request to sign Transaction
|
||||
|
|
@ -100,7 +100,7 @@ func (ui *CommandlineUI) ApproveTx(request *SignTxRequest) (SignTxResponse, erro
|
|||
weival := request.Transaction.Value
|
||||
|
||||
fmt.Printf("--------- Transaction request-------------\n")
|
||||
fmt.Printf("to: %v\n", request.Transaction.To.Hex())
|
||||
fmt.Printf("to: %v\n", request.Transaction.To)
|
||||
fmt.Printf("from: %v\n", request.From.Hex())
|
||||
fmt.Printf("value: %v wei\n", weival)
|
||||
if len(request.Transaction.Data) > 0 {
|
||||
|
|
@ -125,7 +125,7 @@ func (ui *CommandlineUI) ApproveSignData(request *SignDataRequest) (SignDataResp
|
|||
|
||||
fmt.Printf("-------- Sign data request--------------\n")
|
||||
fmt.Printf("Account: %x\n", request.Address)
|
||||
fmt.Printf("message: \n%v\n", request.Message)
|
||||
fmt.Printf("message: \n%q\n", request.Message)
|
||||
fmt.Printf("raw data: \n%v\n", request.Rawdata)
|
||||
fmt.Printf("message hash: %v\n", request.Hash)
|
||||
fmt.Printf("-------------------------------------------\n")
|
||||
|
|
@ -154,7 +154,7 @@ func (ui *CommandlineUI) ApproveImport(request *ImportRequest) (ImportResponse,
|
|||
ui.mu.Lock()
|
||||
defer ui.mu.Unlock()
|
||||
|
||||
fmt.Printf("-------- Export Account request--------------\n")
|
||||
fmt.Printf("-------- Import Account request--------------\n")
|
||||
fmt.Printf("A request has been made to import an encrypted keyfile\n")
|
||||
fmt.Printf("-------------------------------------------\n")
|
||||
showMetadata(request.Meta)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
|
@ -84,6 +87,10 @@ func main() {
|
|||
"This means that an STDIN/STDOUT is used for RPC-communication with a e.g. a graphical user " +
|
||||
"interface, and can be used when the signer is started by an external process.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "stdio-ui-test",
|
||||
Usage: "Mechanism to test interface between signer and UI. Requires 'stdio-ui'.",
|
||||
},
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
|
|
@ -136,6 +143,7 @@ func main() {
|
|||
if err = server.RegisterName("account", api); err != nil {
|
||||
utils.Fatalf("Could not register signer API: %v", err)
|
||||
}
|
||||
//server.ListServices()
|
||||
|
||||
// Import from file
|
||||
if rfile := c.String("requestfile"); rfile != "" {
|
||||
|
|
@ -151,13 +159,63 @@ func main() {
|
|||
log.Info("HTTP endpoint opened", "url", fmt.Sprintf("http://%s", endpoint))
|
||||
cors := []string{"*"}
|
||||
|
||||
if c.Bool("stdio-ui-test") {
|
||||
log.Info("Performing UI test")
|
||||
go testExternalUI(api)
|
||||
}
|
||||
|
||||
rpc.NewHTTPServer(cors, server).Serve(listener)
|
||||
|
||||
return nil
|
||||
}
|
||||
app.Run(os.Args)
|
||||
|
||||
}
|
||||
|
||||
func testExternalUI(api *SignerAPI) {
|
||||
|
||||
ctx := context.WithValue(context.Background(), "remote", "signer binary")
|
||||
ctx = context.WithValue(ctx, "scheme", "in-proc")
|
||||
ctx = context.WithValue(ctx, "local", "main")
|
||||
|
||||
errs := make([]string, 0)
|
||||
|
||||
api.ui.ShowInfo("Testing 'ShowInfo'")
|
||||
api.ui.ShowError("Testing 'ShowError'")
|
||||
|
||||
checkErr:= func(method string, err error){
|
||||
if err != nil && err != ErrRequestDenied{
|
||||
errs = append(errs, fmt.Sprintf("%v: %v", method, err.Error()))
|
||||
}
|
||||
}
|
||||
var err error
|
||||
|
||||
_, err = api.SignTransaction(ctx, common.Address{}, TransactionArg{}, nil);
|
||||
checkErr("SignTransaction", err)
|
||||
_, err = api.Sign(ctx, common.Address{}, common.Hex2Bytes("01020304"))
|
||||
checkErr("Sign", err)
|
||||
_, err =api.List(ctx)
|
||||
checkErr("List", err)
|
||||
_, err = api.New(ctx)
|
||||
checkErr("New", err)
|
||||
_, err = api.Export(ctx, common.Address{})
|
||||
checkErr("Export", err)
|
||||
_, err = api.Import(ctx, json.RawMessage{})
|
||||
checkErr("Import", err)
|
||||
|
||||
api.ui.ShowInfo("Tests completed")
|
||||
|
||||
if len(errs) > 0 {
|
||||
log.Error("Got errors")
|
||||
for _, e := range errs {
|
||||
log.Error(e)
|
||||
}
|
||||
}else{
|
||||
log.Info("No errors")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Create Account
|
||||
// curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_new","params":["test"],"id":67}' localhost:8550
|
||||
|
||||
|
|
|
|||
|
|
@ -34,60 +34,117 @@ class PipeTransport(ServerTransport):
|
|||
|
||||
def receive_message(self):
|
||||
data = self.input.readline()
|
||||
print("IN ->\n{}".format( data))
|
||||
#print(">> {}".format( data))
|
||||
return None, urlparse.unquote(data)
|
||||
|
||||
def send_reply(self, context, reply):
|
||||
print("OUT <-\n{}".format( reply))
|
||||
#print("<< {}".format( reply))
|
||||
self.output.write(reply)
|
||||
self.output.write("\n")
|
||||
|
||||
dispatcher = RPCDispatcher()
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveTx(Transaction = None, From = None, Callinfo = None, Meta = None):
|
||||
def ApproveTx(transaction = None, fromaccount = None, call_info = None, meta = None):
|
||||
"""
|
||||
Example request:
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveTx","params":{"transaction":{"to":null,"gas":null,"gasPrice":null,"value":null,"data":"0x","nonce":null},"from":"0x0000000000000000000000000000000000000000","call_info":null,"meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":2}
|
||||
|
||||
:param transaction: transaction info
|
||||
:param call_info: info abou the call, e.g. if ABI info could not be
|
||||
:param meta: metadata about the request, e.g. where the call comes from
|
||||
:return:
|
||||
"""
|
||||
return {
|
||||
"Approved" : True,
|
||||
"Transaction" : Transaction,
|
||||
"From" : From,
|
||||
"Password" : None,
|
||||
"approved" : False,
|
||||
"transaction" : None,
|
||||
"fromaccount" : fromaccount,
|
||||
"password" : None,
|
||||
}
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveSignData():
|
||||
return {"Approved": False,
|
||||
"Password" : None}
|
||||
def ApproveSignData(address=None, raw_data = None, message = None, hash = None, meta = None):
|
||||
""" Example request
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveSignData","params":{"address":"0x0000000000000000000000000000000000000000","raw_data":"0x01020304","message":"\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004","hash":"0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310","meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":3}
|
||||
|
||||
|
||||
"""
|
||||
return {"approved": False,
|
||||
"password" : None}
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveExport():
|
||||
return {"Approved" : False}
|
||||
def ApproveExport(address = None, meta = None):
|
||||
""" Example request
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveExport","params":{"address":"0x0000000000000000000000000000000000000000","meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":5}
|
||||
|
||||
"""
|
||||
return {"approved" : False}
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveImport():
|
||||
return {"Approved" : False, "OldPassword": "", "NewPassword": ""}
|
||||
def ApproveImport(meta = None):
|
||||
""" Example request
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveImport","params":{"Meta":{}},"id":4}
|
||||
|
||||
"""
|
||||
return {"approved" : False, "old_password": "", "new_password": ""}
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveListing():
|
||||
return []
|
||||
def ApproveListing(accounts=None, meta = None):
|
||||
""" Example request
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveListing","params":{"accounts":[{"type":"Account","url":"keystore:///home/user/ethereum/keystore/file","address":"0x010101010101010010101010101abcdef0001337"}],"Meta":{}},"id":2}
|
||||
"""
|
||||
return {'accounts': []}
|
||||
|
||||
@dispatcher.public
|
||||
def ApproveNewAccount():
|
||||
return {"Approved": False, "Password": ""}
|
||||
def ApproveNewAccount(meta = None):
|
||||
"""
|
||||
Example request
|
||||
|
||||
{"jsonrpc":"2.0","method":"ApproveNewAccount","params":{"meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":5}
|
||||
|
||||
:return:
|
||||
"""
|
||||
return {"approved": False, "password": ""}
|
||||
|
||||
@dispatcher.public
|
||||
def ShowError(text = ""):
|
||||
sys.err.println("Error: %s", text)
|
||||
def ShowError(message = ""):
|
||||
"""
|
||||
Example request:
|
||||
|
||||
{"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowError'"},"id":1}
|
||||
|
||||
:param text: to show
|
||||
:return: nothing
|
||||
"""
|
||||
sys.stderr.write("Error: {}\n".format( message))
|
||||
return
|
||||
|
||||
@dispatcher.public
|
||||
def ShowInfo(text = ""):
|
||||
sys.err.println("Info: %s", text)
|
||||
def ShowInfo(message = ""):
|
||||
"""
|
||||
Example request
|
||||
{"jsonrpc":"2.0","method":"ShowInfo","params":{"message":"Testing 'ShowInfo'"},"id":0}
|
||||
|
||||
:param text: to display
|
||||
:return:nothing
|
||||
"""
|
||||
sys.stdout.write("Info: {}\n".format( message))
|
||||
return
|
||||
|
||||
|
||||
def main():
|
||||
def main(args):
|
||||
|
||||
cmd = ["./signer", "--stdio-ui"]
|
||||
if len(args) > 0 and args[0] == "test":
|
||||
cmd.extend(["--stdio-ui-test"])
|
||||
print("cmd: {}".format(" ".join(cmd)))
|
||||
# line buffered
|
||||
p = subprocess.Popen(["./signer", "--stdio-ui"], bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
p = subprocess.Popen(cmd, bufsize=1, universal_newlines=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
transport = PipeTransport(p.stdout, p.stdin)
|
||||
rpc_server = RPCServer(
|
||||
transport,
|
||||
|
|
@ -97,4 +154,4 @@ def main():
|
|||
rpc_server.serve_forever()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main(sys.argv[1:])
|
||||
|
|
@ -109,9 +109,17 @@ func (ui StdIOUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountRespo
|
|||
}
|
||||
|
||||
func (ui StdIOUI) ShowError(message string) {
|
||||
err := ui.dispatch("ShowError", &Message{message}, nil)
|
||||
if err != nil {
|
||||
log.Info("Error calling 'ShowError'", "exc", err.Error(),"msg", message)
|
||||
}
|
||||
}
|
||||
|
||||
func (ui StdIOUI) ShowInfo(message string) {
|
||||
err := ui.dispatch("ShowInfo", Message{message}, nil)
|
||||
if err != nil {
|
||||
log.Info("Error calling 'ShowInfo'", "exc", err.Error(), "msg", message)
|
||||
}
|
||||
}
|
||||
|
||||
type rwc struct {
|
||||
|
|
|
|||
Loading…
Reference in a new issue