signer: refactoring + documentation

This commit is contained in:
Martin Holst Swende 2018-02-15 11:46:04 +01:00
parent a8e68b9cc3
commit 99dd0a1b58
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
12 changed files with 175 additions and 122 deletions

View file

@ -174,9 +174,9 @@ None
Signs a transactions and responds with the signed transaction in RLP encoded form.
#### Arguments
1. from [address]: account to send the transaction from
2. transaction object:
- `to` [address]: receiver account
- `from` [address]: account to send the transaction from
- `to` [address]: receiver account. If omitted or `0x`, will cause contract creation.
- `gas` [number]: maximum amount of gas to burn
- `gasPrice` [number]: gas price
- `value` [number:optional]: amount of Wei to send with the transaction
@ -196,8 +196,8 @@ None
"jsonrpc": "2.0",
"method": "account_signTransaction",
"params": [
"0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
{
"from": "0x1923f626bb8dc025849e00f99c25fe2b2f7fb0db",
"gas": "0x55555",
"gasPrice": "0x1234",
"input": "0xabcd",
@ -209,11 +209,64 @@ None
}
{
"id": 2,
"jsonrpc": "2.0",
"result": "0xf86480821234830555559407a565b7ed7d7a678680a4c162885bedbb695fe0821234802ea028f9ebeff90732eae45692a11c4ca2ef7f631a0a25bf8763d093e770c4ec464aa01fae77b24617913e718b989be78bc1aabb2fed3f2d4e3b93bd36759f1b5b4904"
"id": 67,
"error": {
"code": -32000,
"message": "Request denied"
}
}
```
#### Sample call with ABI-data
```
{
"jsonrpc": "2.0",
"method": "account_signTransaction",
"params": [
{
"from": "0x694267f14675d7e1b9494fd8d72fefe1755710fa",
"gas": "0x333",
"gasPrice": "0x1",
"nonce": "0x0",
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
"value": "0x0",
"data": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"
},
"safeSend(address)"
],
"id": 67
}
{
"jsonrpc": "2.0",
"id": 67,
"result": {
"raw": "0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
"tx": {
"nonce": "0x0",
"gasPrice": "0x1",
"gas": "0x333",
"to": "0x07a565b7ed7d7a678680a4c162885bedbb695fe0",
"value": "0x0",
"input": "0x4401a6e40000000000000000000000000000000000000000000000000000000000000012",
"v": "0x26",
"r": "0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e",
"s": "0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663",
"hash": "0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"
}
}
}
```
Bash example:
```bash
#curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"account_signTransaction","params":[{"from":"0x694267f14675d7e1b9494fd8d72fefe1755710fa","gas":"0x333","gasPrice":"0x1","nonce":"0x0","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0", "value":"0x0", "data":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012"},"safeSend(address)"],"id":67}' http://localhost:8550/
{"jsonrpc":"2.0","id":67,"result":{"raw":"0xf88380018203339407a565b7ed7d7a678680a4c162885bedbb695fe080a44401a6e4000000000000000000000000000000000000000000000000000000000000001226a0223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20ea02aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","tx":{"nonce":"0x0","gasPrice":"0x1","gas":"0x333","to":"0x07a565b7ed7d7a678680a4c162885bedbb695fe0","value":"0x0","input":"0x4401a6e40000000000000000000000000000000000000000000000000000000000000012","v":"0x26","r":"0x223a7c9bcf5531c99be5ea7082183816eb20cfe0bbc322e97cc5c7f71ab8b20e","s":"0x2aadee6b34b45bb15bc42d9c09de4a6754e7000908da72d48cc7704971491663","hash":"0xeba2df809e7a612a0a0d444ccfa5c839624bdc00dd29e3340d46df3870f8a30e"}}}
```
### account_sign
@ -395,7 +448,8 @@ By starting the signer with the switch `--stdio-ui-test`, the signer will invoke
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**
All methods in this API uses object-based parameters, so that there can be no mixups of parameters: each piece of data is accessed by key.
### ApproveTx
@ -560,6 +614,15 @@ The UI should show the info to the user. Does not expect response.
```
### OnApproved
`OnApprovedTx` is called when a transaction has been approved and signed. The call contains the return value that will be sent to the external caller. The return value from this method is ignored - the reason for having this callback is to allow the ruleset to keep track of approved transactions.
When implementing rate-limited rules, this callback should be used.
TLDR; Use this method to keep track of signed transactions, instead of using the data in `ApproveTx`.
### Rules for UI apis
A UI should conform to the following rules.

View file

@ -14,7 +14,7 @@
// 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 signer
package core
import (
// "bytes"
@ -157,25 +157,25 @@ func MethodSelectorToAbi(selector string) ([]byte, error) {
}
type abiDb struct {
type AbiDb struct {
db map[string]string
}
// NewAbiDBFromFile loads signature database from file, and
// errors if the file is not valid json. Does no other validation of contents
func NewAbiDBFromFile(path string) (*abiDb, error) {
func NewAbiDBFromFile(path string) (*AbiDb, error) {
raw, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
db := new(abiDb)
db := new(AbiDb)
json.Unmarshal(raw, &db.db)
return db, nil
}
// LookupMethodSelector checks the given 4byte-sequence against the known ABI methods.
// OBS: This method does not validate the match, it's assumed the caller will do so
func (db *abiDb) LookupMethodSelector(id []byte) (string, error) {
func (db *AbiDb) LookupMethodSelector(id []byte) (string, error) {
if len(id) != 4 {
return "", fmt.Errorf("Expected 4-byte id, got %d", len(id))
}
@ -185,6 +185,6 @@ func (db *abiDb) LookupMethodSelector(id []byte) (string, error) {
}
return "", fmt.Errorf("Signature %v not found", sig)
}
func (db *abiDb) Size() int {
func (db *AbiDb) Size() int {
return len(db.db)
}

View file

@ -14,7 +14,7 @@
// 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 signer
package core
import (
"fmt"
@ -176,13 +176,13 @@ func TestCalldataDecoding(t *testing.T) {
func TestSelectorUnmarshalling(t *testing.T) {
var (
db *abiDb
db *AbiDb
err error
abistring []byte
abistruct abi.ABI
)
db, err = NewAbiDBFromFile("4byte.json")
db, err = NewAbiDBFromFile("../4byte.json")
if err != nil {
t.Fatal(err)
}

View file

@ -14,7 +14,7 @@
// 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 signer
package core
import (
"context"
@ -69,7 +69,7 @@ type SignerUI interface {
// ApproveImport prompt the user for confirmation to import Account json
ApproveImport(request *ImportRequest) (ImportResponse, error)
// ApproveListing prompt the user for confirmation to list accounts
// the list of accounts to list can be modified by the ui
// the list of accounts to list can be modified by the UI
ApproveListing(request *ListRequest) (ListResponse, error)
// ApproveNewAccount prompt the user for confirmation to create new Account, and reveal to caller
ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error)
@ -86,8 +86,8 @@ type SignerUI interface {
type SignerAPI struct {
chainID *big.Int
am *accounts.Manager
ui SignerUI
abidb abiDb
UI SignerUI
abidb AbiDb
}
// Metadata about a request
@ -201,7 +201,7 @@ func (ew errorWrapper) String() string {
// key that is generated when a new Account is created.
// noUSB disables USB support that is required to support hardware devices such as
// ledger and trezor.
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *abiDb, lightKDF bool) *SignerAPI {
func NewSignerAPI(chainID int64, ksLocation string, noUSB bool, ui SignerUI, abidb *AbiDb, lightKDF bool) *SignerAPI {
var (
backends []accounts.Backend
n, p = keystore.StandardScryptN, keystore.StandardScryptP
@ -242,7 +242,7 @@ func (api *SignerAPI) List(ctx context.Context) (Accounts, error) {
accs = append(accs, acc)
}
}
result, err := api.ui.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)})
result, err := api.UI.ApproveListing(&ListRequest{Accounts: accs, Meta: MetadataFromContext(ctx)})
if err != nil {
return nil, err
}
@ -261,7 +261,7 @@ func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) {
if len(be) == 0 {
return accounts.Account{}, errors.New("password based accounts not supported")
}
resp, err := api.ui.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)})
resp, err := api.UI.ApproveNewAccount(&NewAccountRequest{MetadataFromContext(ctx)})
if err != nil {
return accounts.Account{}, err
@ -277,33 +277,25 @@ func (api *SignerAPI) New(ctx context.Context) (accounts.Account, error) {
// UI-modifications to requests
func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
modified := false
if f0, f1 := original.Transaction.From, new.Transaction.From; !reflect.DeepEqual(f0, f1) {
log.Info("Sender-account changed by UI", "was", f0, "is", f1)
modified = true
}
if t0, t1 := original.Transaction.To, new.Transaction.To; !reflect.DeepEqual(t0, t1) {
log.Info("Recipient-account changed by UI", "was", t0, "is", t1)
modified = true
}
if g0, g1 := (*big.Int)(original.Transaction.Gas), (*big.Int)(new.Transaction.Gas); g0 != g1 {
if g0 == nil || g1 == nil || g0.Cmp(g1) != 0 {
modified = true
log.Info("Gas changed by UI", "was", g0, "is", g1)
}
if g0, g1 := big.Int(original.Transaction.Gas), big.Int(new.Transaction.Gas); g0.Cmp(&g1) != 0 {
modified = true
log.Info("Gas changed by UI", "was", g0, "is", g1)
}
if g0, g1 := (*big.Int)(original.Transaction.GasPrice), (*big.Int)(new.Transaction.GasPrice); g0 != g1 {
if g0 == nil || g1 == nil || g0.Cmp(g1) != 0 {
modified = true
log.Info("GasPrice changed by UI", "was", g0, "is", g1)
}
if g0, g1 := big.Int(original.Transaction.GasPrice), big.Int(new.Transaction.GasPrice); g0.Cmp(&g1) != 0 {
modified = true
log.Info("GasPrice changed by UI", "was", g0, "is", g1)
}
if v0, v1 := (*big.Int)(original.Transaction.Value), (*big.Int)(new.Transaction.Value); v0 != v1 {
if v0 == nil || v1 == nil || v0.Cmp(v1) != 0 {
modified = true
log.Info("Value changed by UI", "was", v0, "is", v1)
}
if v0, v1 := big.Int(original.Transaction.Value), big.Int(new.Transaction.Value); v0.Cmp(&v1) != 0 {
modified = true
log.Info("Value changed by UI", "was", v0, "is", v1)
}
if d0, d1 := original.Transaction.Data, new.Transaction.Data; d0 != d1 {
d0s := ""
@ -320,11 +312,8 @@ func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
}
}
if n0, n1 := original.Transaction.Nonce, new.Transaction.Nonce; n0 != n1 {
if n0 == nil || n1 == nil || (*n0) != (*n1) {
modified = true
log.Info("Nonce changed by UI", "was", n0, "is", n1)
}
modified = true
log.Info("Nonce changed by UI", "was", n0, "is", n1)
}
return modified
}
@ -386,12 +375,12 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
*args.Input = nil
}
req := SignTxRequest{
Transaction: args,
Meta: MetadataFromContext(ctx),
Callinfo:api.determineCallInfo(data, methodSelector),
Transaction: args,
Meta: MetadataFromContext(ctx),
Callinfo: api.determineCallInfo(data, methodSelector),
}
// Process approval
result, err = api.ui.ApproveTx(&req)
result, err = api.UI.ApproveTx(&req)
if err != nil {
return nil, err
}
@ -415,7 +404,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
// The one to sign is the one that was returned from the UI
signedTx, err := wallet.SignTxWithPassphrase(acc, result.Password, unsignedTx, api.chainID)
if err != nil {
api.ui.ShowError(err.Error())
api.UI.ShowError(err.Error())
return nil, err
}
@ -423,7 +412,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args SendTxArgs, meth
response := ethapi.SignTransactionResult{rlpdata, signedTx}
// Finally, send the signed tx to the UI
api.ui.OnApprovedTx(response)
api.UI.OnApprovedTx(response)
// ...and to the external caller
return &response, nil
@ -443,7 +432,7 @@ func (api *SignerAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, da
// We make the request prior to looking up if we actually have the account, to prevent
// account-enumeration via the API
req := &SignDataRequest{Address: addr, Rawdata: data, Message: msg, Hash: sighash, Meta: MetadataFromContext(ctx)}
res, err := api.ui.ApproveSignData(req)
res, err := api.UI.ApproveSignData(req)
if err != nil {
return nil, err
@ -460,7 +449,7 @@ func (api *SignerAPI) Sign(ctx context.Context, addr common.MixedcaseAddress, da
// Assemble sign the data with the wallet
signature, err := wallet.SignHashWithPassphrase(account, res.Password, sighash)
if err != nil {
api.ui.ShowError(err.Error())
api.UI.ShowError(err.Error())
return nil, err
}
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
@ -509,7 +498,7 @@ func signHash(data []byte) ([]byte, string) {
// Export returns encrypted private key associated with the given address in web3 keystore format.
func (api *SignerAPI) Export(ctx context.Context, addr common.Address) (json.RawMessage, error) {
res, err := api.ui.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
res, err := api.UI.ApproveExport(&ExportRequest{Address: addr, Meta: MetadataFromContext(ctx)})
if err != nil {
return nil, err
@ -537,7 +526,7 @@ func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Acco
if len(be) == 0 {
return Account{}, errors.New("password based accounts not supported")
}
res, err := api.ui.ApproveImport(&ImportRequest{Meta: MetadataFromContext(ctx)})
res, err := api.UI.ApproveImport(&ImportRequest{Meta: MetadataFromContext(ctx)})
if err != nil {
return Account{}, err
@ -547,7 +536,7 @@ func (api *SignerAPI) Import(ctx context.Context, keyJSON json.RawMessage) (Acco
}
acc, err := be[0].(*keystore.KeyStore).Import(keyJSON, res.OldPassword, res.NewPassword)
if err != nil {
api.ui.ShowError(err.Error())
api.UI.ShowError(err.Error())
return Account{}, err
}
return Account{Typ: "Account", URL: acc.URL, Address: acc.Address}, nil

View file

@ -1,4 +1,4 @@
package signer
package core
import (
"bytes"
@ -35,9 +35,9 @@ func (ui *HeadlessUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error)
case "Y":
return SignTxResponse{request.Transaction, true, <-ui.controller}, nil
case "M": //Modify
old := (*big.Int)(request.Transaction.Value)
newVal := big.NewInt(0).Add(old, big.NewInt(1))
request.Transaction.Value = (*hexutil.Big)(newVal)
old := big.Int(request.Transaction.Value)
newVal := big.NewInt(0).Add(&old, big.NewInt(1))
request.Transaction.Value = hexutil.Big(*newVal)
return SignTxResponse{request.Transaction, true, <-ui.controller}, nil
default:
return SignTxResponse{request.Transaction, false, ""}, nil
@ -106,7 +106,7 @@ func setup(t *testing.T) (*SignerAPI, chan string) {
controller := make(chan string, 10)
db, err := NewAbiDBFromFile(fmt.Sprintf("./4byte.json"))
db, err := NewAbiDBFromFile(fmt.Sprintf("../4byte.json"))
if err != nil {
utils.Fatalf(err.Error())
@ -238,9 +238,9 @@ func TestSignData(t *testing.T) {
}
func mkTestTx(from common.MixedcaseAddress) SendTxArgs {
to := common.NewMixedcaseAddress(common.HexToAddress("0x1337"))
gas := (*hexutil.Big)(big.NewInt(21000))
gasPrice := (*hexutil.Big)(big.NewInt(2000000000))
value := (*hexutil.Big)(big.NewInt(1e18))
gas := (hexutil.Big)(*big.NewInt(21000))
gasPrice := (hexutil.Big)(*big.NewInt(2000000000))
value := (hexutil.Big)(*big.NewInt(1e18))
nonce := (hexutil.Uint64)(0)
data := hexutil.Bytes(common.Hex2Bytes("01020304050607080a"))
tx := SendTxArgs{
@ -250,7 +250,7 @@ func mkTestTx(from common.MixedcaseAddress) SendTxArgs {
GasPrice: gasPrice,
Value: value,
Data: &data,
Nonce: &nonce}
Nonce: nonce}
return tx
}

View file

@ -14,7 +14,7 @@
// 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 signer
package core
import (
"context"

View file

@ -13,7 +13,7 @@
//
// 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 signer
package core
import (
"bufio"
@ -181,7 +181,7 @@ func (ui *CommandlineUI) ApproveImport(request *ImportRequest) (ImportResponse,
}
// ApproveListing prompt the user for confirmation to list accounts
// the list of accounts to list can be modified by the ui
// the list of accounts to list can be modified by the UI
func (ui *CommandlineUI) ApproveListing(request *ListRequest) (ListResponse, error) {
ui.mu.Lock()

View file

@ -15,7 +15,7 @@
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
//
package signer
package core
import (
"context"

View file

@ -14,7 +14,7 @@
// 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 signer
package core
import (
"encoding/json"
@ -66,10 +66,10 @@ type TransactionArg struct {
type SendTxArgs struct {
From common.MixedcaseAddress `json:"from"`
To *common.MixedcaseAddress `json:"to"`
Gas *hexutil.Big `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"`
Nonce *hexutil.Uint64 `json:"nonce"`
Gas hexutil.Big `json:"gas"`
GasPrice hexutil.Big `json:"gasPrice"`
Value hexutil.Big `json:"value"`
Nonce hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons.
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
@ -91,7 +91,7 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
input = *args.Input
}
if args.To == nil {
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input)
return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), (*big.Int)(&args.Gas), (*big.Int)(&args.GasPrice), input)
}
return types.NewTransaction(uint64(*args.Nonce), (*args.To).Address(), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input)
return types.NewTransaction(uint64(args.Nonce), args.To.Address(), (*big.Int)(&args.Value), (*big.Int)(&args.Gas), (*big.Int)(&args.GasPrice), input)
}

View file

@ -16,7 +16,7 @@
// signer is a utility that can be used so sign transactions and
// arbitrary data.
package signer
package main
import (
"fmt"
@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/rpc"
"gopkg.in/urfave/cli.v1"
"github.com/ethereum/go-ethereum/cmd/signer/core"
)
func main() {
@ -90,7 +91,7 @@ func main() {
app.Action = func(c *cli.Context) error {
var (
ui SignerUI
ui core.SignerUI
)
// Set up the logger to print everything
logOutput := os.Stdout
@ -100,14 +101,14 @@ func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(logOutput, log.TerminalFormat(true))))
if c.Bool("stdio-ui") {
ui = NewStdIOUI()
ui = core.NewStdIOUI()
} else {
ui = NewCommandlineUI()
ui = core.NewCommandlineUI()
}
if c.Bool("stdio-ui") {
log.Info("Using stdin/stdout as UI-channel")
}
db, err := NewAbiDBFromFile(c.String("4bytedb"))
db, err := core.NewAbiDBFromFile(c.String("4bytedb"))
if err != nil {
utils.Fatalf(err.Error())
@ -115,12 +116,12 @@ func main() {
log.Info("Loaded 4byte db", "signatures", db.Size(), "file", c.String("4bytedb"))
var (
api ExternalAPI
api core.ExternalAPI
listener net.Listener
server = rpc.NewServer()
)
api_impl := NewSignerAPI(
api_impl := core.NewSignerAPI(
c.Int64(utils.NetworkIdFlag.Name),
c.String("keystore"),
c.Bool(utils.NoUSBFlag.Name),
@ -131,7 +132,7 @@ func main() {
// Audit logging
if logfile := c.String("auditlog"); logfile != "" {
api, err = NewAuditLogger(logfile, api_impl)
api, err = core.NewAuditLogger(logfile, api_impl)
if err != nil {
utils.Fatalf(err.Error())
}
@ -170,7 +171,7 @@ func main() {
}
func testExternalUI(api *SignerAPI) {
func testExternalUI(api *core.SignerAPI) {
ctx := context.WithValue(context.Background(), "remote", "signer binary")
ctx = context.WithValue(ctx, "scheme", "in-proc")
@ -178,17 +179,17 @@ func testExternalUI(api *SignerAPI) {
errs := make([]string, 0)
api.ui.ShowInfo("Testing 'ShowInfo'")
api.ui.ShowError("Testing 'ShowError'")
api.UI.ShowInfo("Testing 'ShowInfo'")
api.UI.ShowError("Testing 'ShowError'")
checkErr := func(method string, err error) {
if err != nil && err != ErrRequestDenied {
if err != nil && err != core.ErrRequestDenied {
errs = append(errs, fmt.Sprintf("%v: %v", method, err.Error()))
}
}
var err error
_, err = api.SignTransaction(ctx, SendTxArgs{From:common.MixedcaseAddress{}}, nil)
_, err = api.SignTransaction(ctx, core.SendTxArgs{From:common.MixedcaseAddress{}}, nil)
checkErr("SignTransaction", err)
_, err = api.Sign(ctx, common.MixedcaseAddress{}, common.Hex2Bytes("01020304"))
checkErr("Sign", err)
@ -201,7 +202,7 @@ func testExternalUI(api *SignerAPI) {
_, err = api.Import(ctx, json.RawMessage{})
checkErr("Import", err)
api.ui.ShowInfo("Tests completed")
api.UI.ShowInfo("Tests completed")
if len(errs) > 0 {
log.Error("Got errors")

View file

@ -19,7 +19,6 @@ package rules
import (
"encoding/json"
"fmt"
"github.com/ethereum/go-ethereum/cmd/signer"
"github.com/ethereum/go-ethereum/cmd/signer/rules/deps"
"github.com/ethereum/go-ethereum/cmd/signer/storage"
"github.com/ethereum/go-ethereum/internal/ethapi"
@ -27,6 +26,7 @@ import (
"github.com/robertkrimen/otto"
"os"
"strings"
"github.com/ethereum/go-ethereum/cmd/signer/core"
)
var (
@ -48,7 +48,7 @@ func consoleOutput(call otto.FunctionCall) otto.Value {
// file for each defined UI-method
type rulesetUi struct {
vm *otto.Otto // The JS vm
next signer.SignerUI // The next handler, for manual processing
next core.SignerUI // The next handler, for manual processing
storage storage.Storage
}
@ -104,45 +104,45 @@ func (r *rulesetUi) checkApproval(jsfunc string, jsarg []byte, err error) error
return fmt.Errorf("rejected")
}
func (r *rulesetUi) ApproveTx(request *signer.SignTxRequest) (signer.SignTxResponse, error) {
func (r *rulesetUi) ApproveTx(request *core.SignTxRequest) (core.SignTxResponse, error) {
jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil {
return signer.SignTxResponse{Transaction: request.Transaction, Approved: true, Password: ""}, nil
return core.SignTxResponse{Transaction: request.Transaction, Approved: true, Password: ""}, nil
}
return signer.SignTxResponse{Approved: false}, err
return core.SignTxResponse{Approved: false}, err
}
func (r *rulesetUi) ApproveSignData(request *signer.SignDataRequest) (signer.SignDataResponse, error) {
func (r *rulesetUi) ApproveSignData(request *core.SignDataRequest) (core.SignDataResponse, error) {
jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil {
return signer.SignDataResponse{Approved: true, Password: ""}, nil
return core.SignDataResponse{Approved: true, Password: ""}, nil
}
return signer.SignDataResponse{Approved: false, Password: ""}, err
return core.SignDataResponse{Approved: false, Password: ""}, err
}
func (r *rulesetUi) ApproveExport(request *signer.ExportRequest) (signer.ExportResponse, error) {
func (r *rulesetUi) ApproveExport(request *core.ExportRequest) (core.ExportResponse, error) {
jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveTx", jsonreq, err); err == nil {
return signer.ExportResponse{Approved: true}, nil
return core.ExportResponse{Approved: true}, nil
}
return signer.ExportResponse{Approved: false}, err
return core.ExportResponse{Approved: false}, err
}
func (r *rulesetUi) ApproveImport(request *signer.ImportRequest) (signer.ImportResponse, error) {
func (r *rulesetUi) ApproveImport(request *core.ImportRequest) (core.ImportResponse, error) {
// This cannot be handled by rules, requires setting a password
// dispatch to next
return r.next.ApproveImport(request)
}
func (r *rulesetUi) ApproveListing(request *signer.ListRequest) (signer.ListResponse, error) {
func (r *rulesetUi) ApproveListing(request *core.ListRequest) (core.ListResponse, error) {
jsonreq, err := json.Marshal(request)
if err = r.checkApproval("ApproveListing", jsonreq, err); err == nil {
return signer.ListResponse{Accounts: request.Accounts}, nil
return core.ListResponse{Accounts: request.Accounts}, nil
}
return signer.ListResponse{}, err
return core.ListResponse{}, err
}
func (r *rulesetUi) ApproveNewAccount(request *signer.NewAccountRequest) (signer.NewAccountResponse, error) {
func (r *rulesetUi) ApproveNewAccount(request *core.NewAccountRequest) (core.NewAccountResponse, error) {
// This cannot be handled by rules, requires setting a password
// dispatch to next
return r.next.ApproveNewAccount(request)

View file

@ -3,13 +3,13 @@ package rules
import (
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/signer"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"math/big"
"testing"
"github.com/ethereum/go-ethereum/cmd/signer/core"
)
const JS = `
@ -66,11 +66,11 @@ func initRuleEngine(js string) (*rulesetUi, error) {
}
func TestListRequest(t *testing.T) {
accs := make([]signer.Account, 5)
accs := make([]core.Account, 5)
for i, _ := range accs {
addr := fmt.Sprintf("000000000000000000000000000000000000000%x", i)
acc := signer.Account{
acc := core.Account{
Address: common.BytesToAddress(common.Hex2Bytes(addr)),
URL: accounts.URL{Scheme: "test", Path: fmt.Sprintf("acc-%d", i)},
}
@ -84,9 +84,9 @@ func TestListRequest(t *testing.T) {
t.Errorf("Couldn't create evaluator %v", err)
return
}
resp, err := r.ApproveListing(&signer.ListRequest{
resp, err := r.ApproveListing(&core.ListRequest{
accs,
signer.Metadata{
core.Metadata{
"remoteip", "localip", "inproc",
},
})
@ -126,12 +126,12 @@ func TestSignTxRequest(t *testing.T) {
return
}
fmt.Printf("to %v", to.Address().String())
resp, err := r.ApproveTx(&signer.SignTxRequest{
Transaction: signer.SendTxArgs{
resp, err := r.ApproveTx(&core.SignTxRequest{
Transaction: core.SendTxArgs{
From: *from,
To: to},
Callinfo: "",
Meta: signer.Metadata{"remoteip", "localip", "inproc"},
Meta: core.Metadata{"remoteip", "localip", "inproc"},
})
if err != nil {
t.Errorf("Unexpected error %v", err)
@ -290,7 +290,7 @@ const ExampleTxWindow = `
`
func dummyTx(value *hexutil.Big) *signer.SignTxRequest {
func dummyTx(value hexutil.Big) *core.SignTxRequest {
to, _ := mixAddr("000000000000000000000000000000000000dead")
from, _ := mixAddr("000000000000000000000000000000000000dead")
@ -298,17 +298,17 @@ func dummyTx(value *hexutil.Big) *signer.SignTxRequest {
gas := hexutil.Big(*big.NewInt(21000))
gasPrice := hexutil.Big(*big.NewInt(2000000))
return &signer.SignTxRequest{
Transaction: signer.SendTxArgs{
return &core.SignTxRequest{
Transaction: core.SendTxArgs{
From: *from,
To: to,
Value: value,
Nonce: &n,
GasPrice: &gas,
Gas: &gasPrice,
Nonce: n,
GasPrice: gas,
Gas: gasPrice,
},
Callinfo: "Warning, all your base are bellong to us",
Meta: signer.Metadata{"remoteip", "localip", "inproc"},
Meta: core.Metadata{"remoteip", "localip", "inproc"},
}
}
func dummySigned(value *big.Int) *types.Transaction {
@ -335,7 +335,7 @@ func TestLimitWindow(t *testing.T) {
h := hexutil.Big(*v)
// The first three should succeed
for i := 0; i < 3; i++ {
unsigned := dummyTx(&h)
unsigned := dummyTx(h)
resp, err := r.ApproveTx(unsigned)
if err != nil {
t.Errorf("Unexpected error %v", err)
@ -352,7 +352,7 @@ func TestLimitWindow(t *testing.T) {
r.OnApprovedTx(response)
}
// Fourth should fail
resp, err := r.ApproveTx(dummyTx(&h))
resp, err := r.ApproveTx(dummyTx(h))
if resp.Approved {
t.Errorf("Expected check to resolve to 'Reject'")
}