cmd/clef, signer: initial poc of the standalone signer (#16154)
* signer: introduce external signer command * cmd/signer, rpc: Implement new signer. Add info about remote user to Context * signer: refactored request/response, made use of urfave.cli * cmd/signer: Use common flags * cmd/signer: methods to validate calldata against abi * cmd/signer: work on abi parser * signer: add mutex around UI * cmd/signer: add json 4byte directory, remove passwords from api * cmd/signer: minor changes * cmd/signer: Use ErrRequestDenied, enable lightkdf * cmd/signer: implement tests * cmd/signer: made possible for UI to modify tx parameters * cmd/signer: refactors, removed channels in ui comms, added UI-api via stdin/out * cmd/signer: Made lowercase json-definitions, added UI-signer test functionality * cmd/signer: update documentation * cmd/signer: fix bugs, improve abi detection, abi argument display * cmd/signer: minor change in json format * cmd/signer: rework json communication * cmd/signer: implement mixcase addresses in API, fix json id bug * cmd/signer: rename fromaccount, update pythonpoc with new json encoding format * cmd/signer: make use of new abi interface * signer: documentation * signer/main: remove redundant option * signer: implement audit logging * signer: create package 'signer', minor changes * common: add 0x-prefix to mixcaseaddress in json marshalling + validation * signer, rules, storage: implement rules + ephemeral storage for signer rules * signer: implement OnApprovedTx, change signing response (API BREAKAGE) * signer: refactoring + documentation * signer/rules: implement dispatching to next handler * signer: docs * signer/rules: hide json-conversion from users, ensure context is cleaned * signer: docs * signer: implement validation rules, change signature of call_info * signer: fix log flaw with string pointer * signer: implement custom 4byte databsae that saves submitted signatures * signer/storage: implement aes-gcm-backed credential storage * accounts: implement json unmarshalling of url * signer: fix listresponse, fix gas->uint64 * node: make http/ipc start methods public * signer: add ipc capability+review concerns * accounts: correct docstring * signer: address review concerns * rpc: go fmt -s * signer: review concerns+ baptize Clef * signer,node: move Start-functions to separate file * signer: formatting
This commit is contained in:
committed by
Péter Szilágyi
parent
de2a7bb764
commit
ec3db0f56c
247
signer/core/abihelper_test.go
Normal file
247
signer/core/abihelper_test.go
Normal file
@ -0,0 +1,247 @@
|
||||
// Copyright 2018 The go-ethereum Authors
|
||||
// This file is part of go-ethereum.
|
||||
//
|
||||
// go-ethereum is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// go-ethereum is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"reflect"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
func verify(t *testing.T, jsondata, calldata string, exp []interface{}) {
|
||||
|
||||
abispec, err := abi.JSON(strings.NewReader(jsondata))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cd := common.Hex2Bytes(calldata)
|
||||
sigdata, argdata := cd[:4], cd[4:]
|
||||
method, err := abispec.MethodById(sigdata)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := method.Inputs.UnpackValues(argdata)
|
||||
|
||||
if len(data) != len(exp) {
|
||||
t.Fatalf("Mismatched length, expected %d, got %d", len(exp), len(data))
|
||||
}
|
||||
for i, elem := range data {
|
||||
if !reflect.DeepEqual(elem, exp[i]) {
|
||||
t.Fatalf("Unpack error, arg %d, got %v, want %v", i, elem, exp[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestNewUnpacker(t *testing.T) {
|
||||
type unpackTest struct {
|
||||
jsondata string
|
||||
calldata string
|
||||
exp []interface{}
|
||||
}
|
||||
testcases := []unpackTest{
|
||||
{ // https://solidity.readthedocs.io/en/develop/abi-spec.html#use-of-dynamic-types
|
||||
`[{"type":"function","name":"f", "inputs":[{"type":"uint256"},{"type":"uint32[]"},{"type":"bytes10"},{"type":"bytes"}]}]`,
|
||||
// 0x123, [0x456, 0x789], "1234567890", "Hello, world!"
|
||||
"8be65246" + "00000000000000000000000000000000000000000000000000000000000001230000000000000000000000000000000000000000000000000000000000000080313233343536373839300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000004560000000000000000000000000000000000000000000000000000000000000789000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20776f726c642100000000000000000000000000000000000000",
|
||||
[]interface{}{
|
||||
big.NewInt(0x123),
|
||||
[]uint32{0x456, 0x789},
|
||||
[10]byte{49, 50, 51, 52, 53, 54, 55, 56, 57, 48},
|
||||
common.Hex2Bytes("48656c6c6f2c20776f726c6421"),
|
||||
},
|
||||
}, { // https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI#examples
|
||||
`[{"type":"function","name":"sam","inputs":[{"type":"bytes"},{"type":"bool"},{"type":"uint256[]"}]}]`,
|
||||
// "dave", true and [1,2,3]
|
||||
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
|
||||
[]interface{}{
|
||||
[]byte{0x64, 0x61, 0x76, 0x65},
|
||||
true,
|
||||
[]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)},
|
||||
},
|
||||
}, {
|
||||
`[{"type":"function","name":"send","inputs":[{"type":"uint256"}]}]`,
|
||||
"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
|
||||
[]interface{}{big.NewInt(0x12)},
|
||||
}, {
|
||||
`[{"type":"function","name":"compareAndApprove","inputs":[{"type":"address"},{"type":"uint256"},{"type":"uint256"}]}]`,
|
||||
"751e107900000000000000000000000000000133700000deadbeef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
|
||||
[]interface{}{
|
||||
common.HexToAddress("0x00000133700000deadbeef000000000000000000"),
|
||||
new(big.Int).SetBytes([]byte{0x00}),
|
||||
big.NewInt(0x1),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, c := range testcases {
|
||||
verify(t, c.jsondata, c.calldata, c.exp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func TestReflect(t *testing.T) {
|
||||
a := big.NewInt(0)
|
||||
b := new(big.Int).SetBytes([]byte{0x00})
|
||||
if !reflect.DeepEqual(a, b) {
|
||||
t.Fatalf("Nope, %v != %v", a, b)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func TestCalldataDecoding(t *testing.T) {
|
||||
|
||||
// send(uint256) : a52c101e
|
||||
// compareAndApprove(address,uint256,uint256) : 751e1079
|
||||
// issue(address[],uint256) : 42958b54
|
||||
jsondata := `
|
||||
[
|
||||
{"type":"function","name":"send","inputs":[{"name":"a","type":"uint256"}]},
|
||||
{"type":"function","name":"compareAndApprove","inputs":[{"name":"a","type":"address"},{"name":"a","type":"uint256"},{"name":"a","type":"uint256"}]},
|
||||
{"type":"function","name":"issue","inputs":[{"name":"a","type":"address[]"},{"name":"a","type":"uint256"}]},
|
||||
{"type":"function","name":"sam","inputs":[{"name":"a","type":"bytes"},{"name":"a","type":"bool"},{"name":"a","type":"uint256[]"}]}
|
||||
]`
|
||||
//Expected failures
|
||||
for _, hexdata := range []string{
|
||||
"a52c101e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000042",
|
||||
"a52c101e000000000000000000000000000000000000000000000000000000000000001200",
|
||||
"a52c101e00000000000000000000000000000000000000000000000000000000000000",
|
||||
"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 {
|
||||
t.Errorf("Expected decoding to fail: %s", hexdata)
|
||||
}
|
||||
}
|
||||
|
||||
//Expected success
|
||||
for _, hexdata := range []string{
|
||||
// From https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI
|
||||
"a5643bf20000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000464617665000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003",
|
||||
"a52c101e0000000000000000000000000000000000000000000000000000000000000012",
|
||||
"a52c101eFFffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"751e1079000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||
"42958b54" +
|
||||
// start of dynamic type
|
||||
"0000000000000000000000000000000000000000000000000000000000000040" +
|
||||
//uint256
|
||||
"0000000000000000000000000000000000000000000000000000000000000001" +
|
||||
// length of array
|
||||
"0000000000000000000000000000000000000000000000000000000000000002" +
|
||||
// array values
|
||||
"000000000000000000000000000000000000000000000000000000000000dead" +
|
||||
"000000000000000000000000000000000000000000000000000000000000beef",
|
||||
} {
|
||||
_, err := parseCallData(common.Hex2Bytes(hexdata), jsondata)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected failure on input %s:\n %v (%d bytes) ", hexdata, err, len(common.Hex2Bytes(hexdata)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectorUnmarshalling(t *testing.T) {
|
||||
var (
|
||||
db *AbiDb
|
||||
err error
|
||||
abistring []byte
|
||||
abistruct abi.ABI
|
||||
)
|
||||
|
||||
db, err = NewAbiDBFromFile("../../cmd/clef/4byte.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("DB size %v\n", db.Size())
|
||||
for id, selector := range db.db {
|
||||
|
||||
abistring, err = MethodSelectorToAbi(selector)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
abistruct, err = abi.JSON(strings.NewReader(string(abistring)))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
m, err := abistruct.MethodById(common.Hex2Bytes(id[2:]))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if m.Sig() != selector {
|
||||
t.Errorf("Expected equality: %v != %v", m.Sig(), selector)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCustomABI(t *testing.T) {
|
||||
d, err := ioutil.TempDir("", "signer-4byte-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filename := fmt.Sprintf("%s/4byte_custom.json", d)
|
||||
abidb, err := NewAbiDBFromFiles("../../cmd/clef/4byte.json", filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Now we'll remove all existing signatures
|
||||
abidb.db = make(map[string]string)
|
||||
calldata := common.Hex2Bytes("a52c101edeadbeef")
|
||||
_, err = abidb.LookupMethodSelector(calldata)
|
||||
if err == nil {
|
||||
t.Fatalf("Should not find a match on empty db")
|
||||
}
|
||||
if err = abidb.AddSignature("send(uint256)", calldata); err != nil {
|
||||
t.Fatalf("Failed to save file: %v", err)
|
||||
}
|
||||
_, err = abidb.LookupMethodSelector(calldata)
|
||||
if err != nil {
|
||||
t.Fatalf("Should find a match for abi signature, got: %v", err)
|
||||
}
|
||||
//Check that it wrote to file
|
||||
abidb2, err := NewAbiDBFromFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create new abidb: %v", err)
|
||||
}
|
||||
_, err = abidb2.LookupMethodSelector(calldata)
|
||||
if err != nil {
|
||||
t.Fatalf("Save failed: should find a match for abi signature after loading from disk")
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user