mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
cmd/signer: rename fromaccount, update pythonpoc with new json encoding format
This commit is contained in:
parent
c55fd329ae
commit
f743cdd437
4 changed files with 238 additions and 37 deletions
|
|
@ -377,7 +377,175 @@ None
|
||||||
|
|
||||||
These methods needs to be implemented by a UI listener.
|
These methods needs to be implemented by a UI listener.
|
||||||
|
|
||||||
still work in progress
|
|
||||||
|
By starting the signer with the switch `--stdio-ui-test`, the signer will invoke all known methods, and expect the UI to respond with
|
||||||
|
denials. This can be used during development to ensure that the API is (at least somewhat) correctly implemented.
|
||||||
|
See `pythonsigner`, which can be invoked via `python3 pythonsigner.py test` to perform the 'denial-handshake-test'.
|
||||||
|
|
||||||
|
**work in progress**
|
||||||
|
|
||||||
|
|
||||||
|
### ApproveTx
|
||||||
|
|
||||||
|
Invoked when there's a transaction for approval.
|
||||||
|
|
||||||
|
|
||||||
|
#### Sample call
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "ApproveTx",
|
||||||
|
"params": [{
|
||||||
|
"transaction": {
|
||||||
|
"to": "0xae967917c465db8578ca9024c205720b1a3651A9",
|
||||||
|
"gas": "0x333",
|
||||||
|
"gasPrice": "0x123",
|
||||||
|
"value": "0x10",
|
||||||
|
"data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff",
|
||||||
|
"nonce": "0x0"
|
||||||
|
},
|
||||||
|
"fromaccount": "0xAe967917c465db8578ca9024c205720b1a3651A9",
|
||||||
|
"call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658",
|
||||||
|
"meta": {
|
||||||
|
"remote": "127.0.0.1:34572",
|
||||||
|
"local": "localhost:8550",
|
||||||
|
"scheme": "HTTP/1.1"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### ApproveExport
|
||||||
|
|
||||||
|
Invoked when a request to export an account has been made.
|
||||||
|
|
||||||
|
#### Sample call
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 7,
|
||||||
|
"method": "ApproveExport",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"address": "0x0000000000000000000000000000000000000000",
|
||||||
|
"meta": {
|
||||||
|
"remote": "signer binary",
|
||||||
|
"local": "main",
|
||||||
|
"scheme": "in-proc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### ApproveListing
|
||||||
|
|
||||||
|
Invoked when a request for account listing has been made.
|
||||||
|
|
||||||
|
#### Sample call
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 5,
|
||||||
|
"method": "ApproveListing",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"accounts": [
|
||||||
|
{
|
||||||
|
"type": "Account",
|
||||||
|
"url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-20T14-44-54.089682944Z--123409812340981234098123409812deadbeef42",
|
||||||
|
"address": "0x123409812340981234098123409812deadbeef42"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Account",
|
||||||
|
"url": "keystore:///home/bazonk/.ethereum/keystore/UTC--2017-11-23T21-59-03.199240693Z--cafebabedeadbeef34098123409812deadbeef42",
|
||||||
|
"address": "0xcafebabedeadbeef34098123409812deadbeef42"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"remote": "signer binary",
|
||||||
|
"local": "main",
|
||||||
|
"scheme": "in-proc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### ApproveSignData
|
||||||
|
|
||||||
|
#### Sample call
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 4,
|
||||||
|
"method": "ApproveSignData",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"address": "0x123409812340981234098123409812deadbeef42",
|
||||||
|
"raw_data": "0x01020304",
|
||||||
|
"message": "\u0019Ethereum Signed Message:\n4\u0001\u0002\u0003\u0004",
|
||||||
|
"hash": "0x7e3a4e7a9d1744bc5c675c25e1234ca8ed9162bd17f78b9085e48047c15ac310",
|
||||||
|
"meta": {
|
||||||
|
"remote": "signer binary",
|
||||||
|
"local": "main",
|
||||||
|
"scheme": "in-proc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### ShowInfo
|
||||||
|
|
||||||
|
The UI should show the info to the user. Does not expect response.
|
||||||
|
|
||||||
|
#### Sample call
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 9,
|
||||||
|
"method": "ShowInfo",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"text": "Tests completed"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### ShowError
|
||||||
|
|
||||||
|
The UI should show the info to the user. Does not expect response.
|
||||||
|
|
||||||
|
```json
|
||||||
|
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 2,
|
||||||
|
"method": "ShowError",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"text": "Testing 'ShowError'"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
### Rules for UI apis
|
### Rules for UI apis
|
||||||
|
|
||||||
|
|
@ -398,6 +566,9 @@ A UI should conform to the following rules.
|
||||||
along with the UI.
|
along with the UI.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
Some snags and todos
|
Some snags and todos
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
type decodedArgument struct {
|
type decodedArgument struct {
|
||||||
|
|
@ -82,18 +83,29 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
|
||||||
if method == nil {
|
if method == nil {
|
||||||
return nil, fmt.Errorf("Supplied ABI spec does not contain method signature in data: 0x%x", sigdata)
|
return nil, fmt.Errorf("Supplied ABI spec does not contain method signature in data: 0x%x", sigdata)
|
||||||
}
|
}
|
||||||
|
var v interface{}
|
||||||
|
method.Inputs.Unpack(v, argdata)
|
||||||
|
|
||||||
|
ref := reflect.ValueOf(v)
|
||||||
|
values := make([]interface{}, ref.NumField())
|
||||||
|
|
||||||
|
for i := 0; i < ref.NumField(); i++ {
|
||||||
|
values[i] = ref.Field(i).Interface()
|
||||||
|
}
|
||||||
|
fmt.Println(values)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
decoded := decodedCallData{signature: method.Sig(), name: method.Name}
|
decoded := decodedCallData{signature: method.Sig(), name: method.Name}
|
||||||
|
|
||||||
|
/*
|
||||||
for n, argument := range method.Inputs {
|
for n, argument := range method.Inputs {
|
||||||
value, err := abi.ToGoType(n*32, argument.Type, argdata)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
|
return nil, fmt.Errorf("Failed to decode argument %d (signature %v): %v", n, method.Sig(), err)
|
||||||
} else {
|
} else {
|
||||||
decodedArg := decodedArgument{
|
decodedArg := decodedArgument{
|
||||||
soltype: argument,
|
soltype: argument,
|
||||||
value: value,
|
value: reflect.ValueOf(v,) ,
|
||||||
}
|
}
|
||||||
decoded.inputs = append(decoded.inputs, decodedArg)
|
decoded.inputs = append(decoded.inputs, decodedArg)
|
||||||
}
|
}
|
||||||
|
|
@ -103,20 +115,19 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
|
||||||
// original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
|
// original data. If we didn't do that, it would e.g. be possible to stuff extra data into the arguments, which
|
||||||
// is not detected by merely decoding the data.
|
// is not detected by merely decoding the data.
|
||||||
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gotypedArguments = make([]interface{}, len(decoded.inputs))
|
|
||||||
encoded []byte
|
encoded []byte
|
||||||
)
|
)
|
||||||
for i, arg := range decoded.inputs {
|
encoded, err = method.Inputs.Pack(v)
|
||||||
gotypedArguments[i] = arg.value
|
|
||||||
}
|
|
||||||
encoded, err = abispec.Pack(method.Name, gotypedArguments...)
|
|
||||||
|
|
||||||
if !bytes.Equal(encoded, calldata) {
|
if !bytes.Equal(encoded, calldata) {
|
||||||
exp := common.Bytes2Hex(encoded)
|
exp := common.Bytes2Hex(encoded)
|
||||||
was := common.Bytes2Hex(calldata)
|
was := common.Bytes2Hex(calldata)
|
||||||
return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig())
|
return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. \nWant %s\nHave %s\nfor method %v", exp, was, method.Sig())
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return &decoded, nil
|
return &decoded, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import (
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/ethereum/go-ethereum/accounts/usbwallet"
|
"github.com/ethereum/go-ethereum/accounts/usbwallet"
|
||||||
|
|
@ -56,7 +58,7 @@ type (
|
||||||
// SignTxRequest contains info about a Transaction to sign
|
// SignTxRequest contains info about a Transaction to sign
|
||||||
SignTxRequest struct {
|
SignTxRequest struct {
|
||||||
Transaction TransactionArg `json:"transaction"`
|
Transaction TransactionArg `json:"transaction"`
|
||||||
From common.MixedcaseAddress `json:"fromaccount"`
|
From common.MixedcaseAddress `json:"from"`
|
||||||
Callinfo string `json:"call_info"`
|
Callinfo string `json:"call_info"`
|
||||||
Meta Metadata `json:"meta"`
|
Meta Metadata `json:"meta"`
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +66,7 @@ type (
|
||||||
SignTxResponse struct {
|
SignTxResponse struct {
|
||||||
//The UI may make changes to the TX
|
//The UI may make changes to the TX
|
||||||
Transaction TransactionArg `json:"transaction"`
|
Transaction TransactionArg `json:"transaction"`
|
||||||
From common.MixedcaseAddress `json:"fromaccount"`
|
From common.MixedcaseAddress `json:"from"`
|
||||||
Approved bool `json:"approved"`
|
Approved bool `json:"approved"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
@ -260,7 +262,7 @@ func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
|
||||||
modified = true
|
modified = true
|
||||||
log.Info("Sender-account changed by UI", "was", f0, "is", f1)
|
log.Info("Sender-account changed by UI", "was", f0, "is", f1)
|
||||||
}
|
}
|
||||||
if t0, t1 := original.Transaction.To, new.Transaction.To; t0 != t1 {
|
if t0, t1 := original.Transaction.To, new.Transaction.To; !reflect.DeepEqual(t0, t1) {
|
||||||
log.Info("Recipient-account changed by UI", "was", t0, "is", t1)
|
log.Info("Recipient-account changed by UI", "was", t0, "is", t1)
|
||||||
modified = true
|
modified = true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,71 +48,87 @@ class StdIOHandler():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveTx(self,transaction = None, fromaccount = None, call_info = None, meta = None):
|
def ApproveTx(self,req):
|
||||||
"""
|
"""
|
||||||
Example request:
|
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}
|
"jsonrpc": "2.0",
|
||||||
|
"method": "ApproveTx",
|
||||||
|
"params": [{
|
||||||
|
"transaction": {
|
||||||
|
"to": "0xae967917c465db8578ca9024c205720b1a3651A9",
|
||||||
|
"gas": "0x333",
|
||||||
|
"gasPrice": "0x123",
|
||||||
|
"value": "0x10",
|
||||||
|
"data": "0xd7a5865800000000000000000000000000000000000000000000000000000000000000ff",
|
||||||
|
"nonce": "0x0"
|
||||||
|
},
|
||||||
|
"from": "0xAe967917c465db8578ca9024c205720b1a3651A9",
|
||||||
|
"call_info": "Warning! Could not validate ABI-data against calldata\nSupplied ABI spec does not contain method signature in data: 0xd7a58658",
|
||||||
|
"meta": {
|
||||||
|
"remote": "127.0.0.1:34572",
|
||||||
|
"local": "localhost:8550",
|
||||||
|
"scheme": "HTTP/1.1"
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
|
||||||
:param transaction: transaction info
|
:param transaction: transaction info
|
||||||
:param call_info: info abou the call, e.g. if ABI info could not be
|
: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
|
:param meta: metadata about the request, e.g. where the call comes from
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
transaction = req.get('transaction')
|
||||||
|
_from = req.get('from')
|
||||||
|
call_info = req.get('call_info')
|
||||||
|
meta = req.get('meta')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"approved" : False,
|
"approved" : False,
|
||||||
"transaction" : None,
|
"transaction" : transaction,
|
||||||
#"fromaccount" : fromaccount,
|
"from" : _from,
|
||||||
"password" : None,
|
# "password" : None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveSignData(self,address=None, raw_data = None, message = None, hash = None, meta = None):
|
def ApproveSignData(self, req):
|
||||||
""" Example request
|
""" 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,
|
return {"approved": False, "password" : None}
|
||||||
"password" : None}
|
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveExport(self,address = None, meta = None):
|
def ApproveExport(self, req):
|
||||||
""" Example request
|
""" Example request
|
||||||
|
|
||||||
{"jsonrpc":"2.0","method":"ApproveExport","params":{"address":"0x0000000000000000000000000000000000000000","meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":5}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return {"approved" : False}
|
return {"approved" : False}
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveImport(self,meta = None):
|
def ApproveImport(self, req):
|
||||||
""" Example request
|
""" Example request
|
||||||
|
|
||||||
{"jsonrpc":"2.0","method":"ApproveImport","params":{"Meta":{}},"id":4}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return {"approved" : False, "old_password": "", "new_password": ""}
|
return { "approved" : False, "old_password": "", "new_password": ""}
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveListing(self,accounts=None, meta = None):
|
def ApproveListing(self, req):
|
||||||
""" Example request
|
""" 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': []}
|
return {'accounts': []}
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ApproveNewAccount(self,meta = None):
|
def ApproveNewAccount(self, req):
|
||||||
"""
|
"""
|
||||||
Example request
|
Example request
|
||||||
|
|
||||||
{"jsonrpc":"2.0","method":"ApproveNewAccount","params":{"meta":{"remote":"signer binary","local":"main","scheme":"in-proc"}},"id":5}
|
|
||||||
|
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
return {"approved": False, "password": ""}
|
return {"approved": False,
|
||||||
|
#"password": ""
|
||||||
|
}
|
||||||
|
|
||||||
@public
|
@public
|
||||||
def ShowError(self,message = {}):
|
def ShowError(self,message = {}):
|
||||||
|
|
@ -137,6 +153,7 @@ class StdIOHandler():
|
||||||
:param message: to display
|
:param message: to display
|
||||||
:return:nothing
|
:return:nothing
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if 'text' in message.keys():
|
if 'text' in message.keys():
|
||||||
sys.stdout.write("Error: {}\n".format( message['text']))
|
sys.stdout.write("Error: {}\n".format( message['text']))
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue