From 37552ecc2201812ecf872941eaab237e8f4e3362 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Sun, 26 Nov 2017 17:16:54 +0100 Subject: [PATCH] cmd/signer: work on abi parser --- cmd/signer/abihelper.go | 8 +++++++- cmd/signer/abihelper_test.go | 10 +++++++++- cmd/signer/api.go | 29 ++++++++++++++++++++++++++++- cmd/signer/cliui.go | 19 ++++++++++++++----- cmd/signer/main.go | 6 ++++++ 5 files changed, 64 insertions(+), 8 deletions(-) diff --git a/cmd/signer/abihelper.go b/cmd/signer/abihelper.go index 7b8a0f525e..5e8a05238f 100644 --- a/cmd/signer/abihelper.go +++ b/cmd/signer/abihelper.go @@ -102,6 +102,12 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) { was := common.Bytes2Hex(calldata) return nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. %v \nWant %s\nHave %s", decoded,was, exp) } - return &decoded, nil } + +func lookupABI(id []byte) (string, error){ + if len(id) != 4{ + return "", fmt.Errorf("Expected 4-byte id, got %d", len(id)) + } + return `[{"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]}]`, nil +} \ No newline at end of file diff --git a/cmd/signer/abihelper_test.go b/cmd/signer/abihelper_test.go index daad0f17a7..3dedfebb40 100644 --- a/cmd/signer/abihelper_test.go +++ b/cmd/signer/abihelper_test.go @@ -21,7 +21,7 @@ import ( "testing" ) -func TestMartin(t *testing.T) { +func TestCalldataDecoding(t *testing.T) { // send(uint256) : a52c101e // compareAndApprove(address,uint256,uint256) : 751e1079 @@ -41,11 +41,19 @@ func TestMartin(t *testing.T) { "a52c101e", "a52c10", "", + // Too short "751e10790000000000000000000000000000000000000000000000000000000000000012", "751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + //Not valid multiple of 32 "deadbeef00000000000000000000000000000000000000000000000000000000000000", + //Too short 'issue' "42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", + // Too short compareAndApprove "a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", + // From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI + // contains a bool with illegal values + "a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", + } { _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata) if err == nil { diff --git a/cmd/signer/api.go b/cmd/signer/api.go index b43ab2e830..c7926276bd 100644 --- a/cmd/signer/api.go +++ b/cmd/signer/api.go @@ -36,6 +36,9 @@ import ( "github.com/ethereum/go-ethereum/rlp" ) +//type Stringer interface {String()} + + type SignerAPI struct { chainID *big.Int am *accounts.Manager @@ -64,6 +67,7 @@ type Credentials struct { type SignTxRequest struct { transaction *types.Transaction from accounts.Account + callinfo fmt.Stringer } type SignTxResponse struct { hash common.Hash @@ -112,6 +116,13 @@ type ListRequest struct { type ListResponse struct { accounts []Account } +type errorWrapper struct{ + msg string + err error +} +func (ew errorWrapper) String() string{ + return fmt.Sprintf("%s\n%s", ew.msg, ew.err) +} // SignerUI specifies what method a UI needs to implement to be able to be used as a UI // for the signer @@ -269,8 +280,24 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, from common.Address, tx = types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) } + req := SignTxRequest{transaction: tx, from: acc} + if len(tx.Data()) > 3{ + var abidef string + + // Try to make sense of the data + abidef, err = lookupABI(tx.Data()[:4]) + if err != nil{ + req.callinfo = errorWrapper{"Warning! Could not locate ABI", err} + }else{ + req.callinfo, err = parseCallData(tx.Data(),abidef) + if err != nil{ + req.callinfo = errorWrapper{"Warning! Could not validate ABI-data against calldata", err} + } + } + } + ch := make(chan SignTxResponse, 1) - api.ui.ApproveTx(&SignTxRequest{transaction: tx, from: acc}, metaData(ctx), ch) + api.ui.ApproveTx(&req, metaData(ctx), ch) if result := <-ch; result.approved { //Sanity check diff --git a/cmd/signer/cliui.go b/cmd/signer/cliui.go index c8c02b5864..30f0ba67ed 100644 --- a/cmd/signer/cliui.go +++ b/cmd/signer/cliui.go @@ -71,19 +71,28 @@ func (ui *CommandlineUI) confirm() bool { } func showMetadata(metadata Metadata) { - fmt.Printf("Request info: %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 func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch chan SignTxResponse) { + weival := request.transaction.Value() + fmt.Printf("--------- Transaction request-------------\n") - fmt.Printf("to: %v\n", request.transaction.To()) - fmt.Printf("from: %v\n", request.from) - fmt.Printf("value: %v\n", request.transaction.Value()) + fmt.Printf("to: %v\n", request.transaction.To().Hex()) + fmt.Printf("from: %v\n", request.from.Address.Hex()) + fmt.Printf("value: %v wei\n", weival) fmt.Printf("data: %v\n", common.Bytes2Hex(request.transaction.Data())) - fmt.Printf("-------------------------------------------\n") + if request.callinfo != nil{ + fmt.Printf("\nNote: This transaction contains data. Review abi-decoding info below:") + fmt.Printf("\nCall info:\n\t%v\n", request.callinfo.String()) + + } + fmt.Printf("\n") showMetadata(metadata) + fmt.Printf("-------------------------------------------\n") + ch <- SignTxResponse{request.transaction.Hash(), ui.confirm(), ""} } diff --git a/cmd/signer/main.go b/cmd/signer/main.go index 7fda49ec7b..707d307717 100644 --- a/cmd/signer/main.go +++ b/cmd/signer/main.go @@ -105,6 +105,12 @@ func main() { // List accounts // curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_list","params":[""],"id":67}' http://localhost:8550/ + +// Make transaction +// send(0x12) +// a52c101e0000000000000000000000000000000000000000000000000000000000000012 +// curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":["0x82A2A876D39022B3019932D30Cd9c97ad5616813","pw",{"gas":"0x333","gasPrice":"0x123","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x10", "input":"0xa52c101e0000000000000000000000000000000000000000000000000000000000000012"}],"id":67}' http://localhost:8550/ + type rwc struct { io.Reader io.Writer