cmd/signer: work on abi parser

This commit is contained in:
Martin Holst Swende 2017-11-26 17:16:54 +01:00
parent 08301bbcc0
commit 37552ecc22
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
5 changed files with 64 additions and 8 deletions

View file

@ -102,6 +102,12 @@ func parseCallData(calldata []byte, abidata string) (*decodedCallData, error) {
was := common.Bytes2Hex(calldata) 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 nil, fmt.Errorf("WARNING: Supplied data is stuffed with extra data. %v \nWant %s\nHave %s", decoded,was, exp)
} }
return &decoded, nil 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
}

View file

@ -21,7 +21,7 @@ import (
"testing" "testing"
) )
func TestMartin(t *testing.T) { func TestCalldataDecoding(t *testing.T) {
// send(uint256) : a52c101e // send(uint256) : a52c101e
// compareAndApprove(address,uint256,uint256) : 751e1079 // compareAndApprove(address,uint256,uint256) : 751e1079
@ -41,11 +41,19 @@ func TestMartin(t *testing.T) {
"a52c101e", "a52c101e",
"a52c10", "a52c10",
"", "",
// Too short
"751e10790000000000000000000000000000000000000000000000000000000000000012", "751e10790000000000000000000000000000000000000000000000000000000000000012",
"751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "751e1079FFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
//Not valid multiple of 32
"deadbeef00000000000000000000000000000000000000000000000000000000000000", "deadbeef00000000000000000000000000000000000000000000000000000000000000",
//Too short 'issue'
"42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", "42958b5400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
// Too short compareAndApprove
"a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042", "a52c101e00ff0000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
// contains a bool with illegal values
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
} { } {
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata) _, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
if err == nil { if err == nil {

View file

@ -36,6 +36,9 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
//type Stringer interface {String()}
type SignerAPI struct { type SignerAPI struct {
chainID *big.Int chainID *big.Int
am *accounts.Manager am *accounts.Manager
@ -64,6 +67,7 @@ type Credentials struct {
type SignTxRequest struct { type SignTxRequest struct {
transaction *types.Transaction transaction *types.Transaction
from accounts.Account from accounts.Account
callinfo fmt.Stringer
} }
type SignTxResponse struct { type SignTxResponse struct {
hash common.Hash hash common.Hash
@ -112,6 +116,13 @@ type ListRequest struct {
type ListResponse struct { type ListResponse struct {
accounts []Account 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 // SignerUI specifies what method a UI needs to implement to be able to be used as a UI
// for the signer // 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) 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) 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 { if result := <-ch; result.approved {
//Sanity check //Sanity check

View file

@ -71,19 +71,28 @@ func (ui *CommandlineUI) confirm() bool {
} }
func showMetadata(metadata Metadata) { 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 // ApproveTx prompt the user for confirmation to request to sign transaction
func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch chan SignTxResponse) { func (ui *CommandlineUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch chan SignTxResponse) {
weival := request.transaction.Value()
fmt.Printf("--------- Transaction request-------------\n") fmt.Printf("--------- Transaction request-------------\n")
fmt.Printf("to: %v\n", request.transaction.To()) fmt.Printf("to: %v\n", request.transaction.To().Hex())
fmt.Printf("from: %v\n", request.from) fmt.Printf("from: %v\n", request.from.Address.Hex())
fmt.Printf("value: %v\n", request.transaction.Value()) fmt.Printf("value: %v wei\n", weival)
fmt.Printf("data: %v\n", common.Bytes2Hex(request.transaction.Data())) 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) showMetadata(metadata)
fmt.Printf("-------------------------------------------\n")
ch <- SignTxResponse{request.transaction.Hash(), ui.confirm(), ""} ch <- SignTxResponse{request.transaction.Hash(), ui.confirm(), ""}
} }

View file

@ -105,6 +105,12 @@ func main() {
// List accounts // List accounts
// curl -i -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_list","params":[""],"id":67}' http://localhost:8550/ // 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 { type rwc struct {
io.Reader io.Reader
io.Writer io.Writer