mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
cmd/signer: implement tests
This commit is contained in:
parent
6f1054a01a
commit
eb61c52626
3 changed files with 325 additions and 1 deletions
294
cmd/signer/api_test.go
Normal file
294
cmd/signer/api_test.go
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Used for testing
|
||||||
|
type HeadlessUI struct {
|
||||||
|
controller chan string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ui *HeadlessUI) ApproveTx(request *SignTxRequest, metadata Metadata, ch chan SignTxResponse) {
|
||||||
|
if "Y" == <-ui.controller {
|
||||||
|
ch <- SignTxResponse{request.transaction.Hash(), true, <-ui.controller}
|
||||||
|
} else {
|
||||||
|
ch <- SignTxResponse{request.transaction.Hash(), false, ""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ApproveSignData(request *SignDataRequest, metadata Metadata, ch chan SignDataResponse) {
|
||||||
|
switch <-ui.controller {
|
||||||
|
case "Y":
|
||||||
|
ch <- SignDataResponse{true, <-ui.controller}
|
||||||
|
default:
|
||||||
|
ch <- SignDataResponse{false, ""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ApproveExport(request *ExportRequest, metadata Metadata, ch chan ExportResponse) {
|
||||||
|
|
||||||
|
switch <-ui.controller {
|
||||||
|
case "Y":
|
||||||
|
ch <- ExportResponse{true}
|
||||||
|
default:
|
||||||
|
ch <- ExportResponse{false}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ApproveImport(request *ImportRequest, metadata Metadata, ch chan ImportResponse) {
|
||||||
|
|
||||||
|
switch <-ui.controller {
|
||||||
|
case "Y":
|
||||||
|
ch <- ImportResponse{true, <-ui.controller, <-ui.controller}
|
||||||
|
default:
|
||||||
|
ch <- ImportResponse{false, "", ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ApproveListing(request *ListRequest, metadata Metadata, ch chan ListResponse) {
|
||||||
|
|
||||||
|
switch <-ui.controller {
|
||||||
|
case "A":
|
||||||
|
ch <- ListResponse{request.accounts}
|
||||||
|
case "1":
|
||||||
|
l := make([]Account, 1)
|
||||||
|
l[0] = request.accounts[1]
|
||||||
|
ch <- ListResponse{l}
|
||||||
|
default:
|
||||||
|
ch <- ListResponse{nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ApproveNewAccount(requst *NewAccountRequest, metadata Metadata, ch chan NewAccountResponse) {
|
||||||
|
|
||||||
|
switch <-ui.controller {
|
||||||
|
case "Y":
|
||||||
|
ch <- NewAccountResponse{true, <-ui.controller}
|
||||||
|
default:
|
||||||
|
ch <- NewAccountResponse{false, ""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ShowError(message string) {
|
||||||
|
//stdout is used by communication
|
||||||
|
fmt.Fprint(os.Stderr, message)
|
||||||
|
}
|
||||||
|
func (ui *HeadlessUI) ShowInfo(message string) {
|
||||||
|
//stdout is used by communication
|
||||||
|
fmt.Fprint(os.Stderr, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tmpDirName(t *testing.T) string {
|
||||||
|
d, err := ioutil.TempDir("", "eth-keystore-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
d, err = filepath.EvalSymlinks(d)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(t *testing.T) (*SignerAPI, chan string) {
|
||||||
|
|
||||||
|
controller := make(chan string, 10)
|
||||||
|
|
||||||
|
db, err := NewAbiDBFromFile(fmt.Sprintf("./4byte.json"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
utils.Fatalf(err.Error())
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
ui = &HeadlessUI{controller}
|
||||||
|
api = NewSignerAPI(
|
||||||
|
1,
|
||||||
|
tmpDirName(t),
|
||||||
|
true,
|
||||||
|
ui,
|
||||||
|
db,
|
||||||
|
true)
|
||||||
|
)
|
||||||
|
return api, controller
|
||||||
|
}
|
||||||
|
func createAccount(control chan string, api *SignerAPI, t *testing.T) {
|
||||||
|
|
||||||
|
control <- "Y"
|
||||||
|
control <- "apassword"
|
||||||
|
_, err := api.New(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Some time to allow changes to propagate
|
||||||
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
}
|
||||||
|
func failCreateAccount(control chan string, api *SignerAPI, t *testing.T) {
|
||||||
|
control <- "N"
|
||||||
|
acc, err := api.New(context.Background())
|
||||||
|
if err != ErrRequestDenied {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if acc.Address != (common.Address{}) {
|
||||||
|
t.Fatal("Empty address should be returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func list(control chan string, api *SignerAPI, t *testing.T) []Account {
|
||||||
|
control <- "A"
|
||||||
|
list, err := api.List(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAcc(t *testing.T) {
|
||||||
|
|
||||||
|
api, control := setup(t)
|
||||||
|
verifyNum := func(num int) {
|
||||||
|
if list := list(control, api, t); len(list) != num {
|
||||||
|
t.Errorf("Expected %d accounts, got %d", num, len(list))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Testing create and create-deny
|
||||||
|
createAccount(control, api, t)
|
||||||
|
createAccount(control, api, t)
|
||||||
|
failCreateAccount(control, api, t)
|
||||||
|
failCreateAccount(control, api, t)
|
||||||
|
createAccount(control, api, t)
|
||||||
|
failCreateAccount(control, api, t)
|
||||||
|
createAccount(control, api, t)
|
||||||
|
failCreateAccount(control, api, t)
|
||||||
|
verifyNum(4)
|
||||||
|
|
||||||
|
// Testing listing:
|
||||||
|
// Listing one account
|
||||||
|
control <- "1"
|
||||||
|
list, err := api.List(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
t.Fatalf("List should only show one account")
|
||||||
|
}
|
||||||
|
// Listing denied
|
||||||
|
control <- "Nope"
|
||||||
|
list, err = api.List(context.Background())
|
||||||
|
if len(list) != 0 {
|
||||||
|
t.Fatalf("List should be empty")
|
||||||
|
}
|
||||||
|
if err != ErrRequestDenied {
|
||||||
|
t.Fatal("Expected deny")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignData(t *testing.T) {
|
||||||
|
|
||||||
|
api, control := setup(t)
|
||||||
|
//Create two accounts
|
||||||
|
createAccount(control, api, t)
|
||||||
|
createAccount(control, api, t)
|
||||||
|
control <- "1"
|
||||||
|
list, err := api.List(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
a := list[0].Address
|
||||||
|
|
||||||
|
control <- "Y"
|
||||||
|
control <- "wrongpassword"
|
||||||
|
h, err := api.Sign(context.Background(), a, []byte("EHLO world"))
|
||||||
|
if h != nil {
|
||||||
|
t.Errorf("Expected nil-data, got %h", h)
|
||||||
|
}
|
||||||
|
if err != keystore.ErrDecrypt {
|
||||||
|
t.Errorf("Expected ErrLocked! %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
control <- "No way"
|
||||||
|
h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
|
||||||
|
if h != nil {
|
||||||
|
t.Errorf("Expected nil-data, got %h", h)
|
||||||
|
}
|
||||||
|
if err != ErrRequestDenied {
|
||||||
|
t.Errorf("Expected ErrRequestDenied! %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
control <- "Y"
|
||||||
|
control <- "apassword"
|
||||||
|
h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if h == nil || len(h) != 65 {
|
||||||
|
t.Errorf("Expected 65 byte signature (got %d bytes)", len(h))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func mkTestTx() TransactionArg {
|
||||||
|
to := common.HexToAddress("0x1337")
|
||||||
|
gas := (*hexutil.Big)(big.NewInt(21000))
|
||||||
|
gasPrice := (*hexutil.Big)(big.NewInt(2000000000))
|
||||||
|
value := (*hexutil.Big)(big.NewInt(1e18))
|
||||||
|
nonce := (hexutil.Uint64)(0)
|
||||||
|
tx := TransactionArg{
|
||||||
|
&to,
|
||||||
|
gas,
|
||||||
|
gasPrice,
|
||||||
|
value,
|
||||||
|
common.Hex2Bytes("01020304050607080a"),
|
||||||
|
&nonce}
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignTx(t *testing.T) {
|
||||||
|
api, control := setup(t)
|
||||||
|
createAccount(control, api, t)
|
||||||
|
control <- "A"
|
||||||
|
list, err := api.List(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
a := list[0].Address
|
||||||
|
|
||||||
|
methodSig := "test(uint)"
|
||||||
|
tx := mkTestTx()
|
||||||
|
|
||||||
|
control <- "Y"
|
||||||
|
control <- "wrongpassword"
|
||||||
|
h, err := api.SignTransaction(context.Background(), a, tx, &methodSig)
|
||||||
|
if h != nil {
|
||||||
|
t.Errorf("Expected nil-data, got %h", h)
|
||||||
|
}
|
||||||
|
if err != keystore.ErrDecrypt {
|
||||||
|
t.Errorf("Expected ErrLocked! %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
control <- "No way"
|
||||||
|
h, err = api.SignTransaction(context.Background(), a, tx, &methodSig)
|
||||||
|
if h != nil {
|
||||||
|
t.Errorf("Expected nil-data, got %h", h)
|
||||||
|
}
|
||||||
|
if err != ErrRequestDenied {
|
||||||
|
t.Errorf("Expected ErrRequestDenied! %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
control <- "Y"
|
||||||
|
control <- "apassword"
|
||||||
|
h, err = api.SignTransaction(context.Background(), a, tx, &methodSig)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if h == nil || len(h) != 118 {
|
||||||
|
t.Errorf("Expected 181 byte rlp-data (got %d bytes)", len(h))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -80,6 +80,7 @@ func main() {
|
||||||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
|
||||||
|
|
||||||
db, err := NewAbiDBFromFile(c.String("4bytedb"))
|
db, err := NewAbiDBFromFile(c.String("4bytedb"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Fatalf(err.Error())
|
utils.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
@ -91,7 +92,8 @@ func main() {
|
||||||
c.Int64(utils.NetworkIdFlag.Name),
|
c.Int64(utils.NetworkIdFlag.Name),
|
||||||
c.String("keystore"),
|
c.String("keystore"),
|
||||||
c.Bool(utils.NoUSBFlag.Name),
|
c.Bool(utils.NoUSBFlag.Name),
|
||||||
NewCommandlineUI(), db)
|
NewCommandlineUI(), db,
|
||||||
|
c.Bool(utils.LightKDFFlag.Name))
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
//err error
|
//err error
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,17 +17,37 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Accounts []Account
|
||||||
|
|
||||||
|
func (as Accounts) String() string{
|
||||||
|
var output []string
|
||||||
|
for _,a := range as{
|
||||||
|
output = append(output, a.String())
|
||||||
|
}
|
||||||
|
return strings.Join(output, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Typ string `json:"type"`
|
Typ string `json:"type"`
|
||||||
URL accounts.URL `json:"url"`
|
URL accounts.URL `json:"url"`
|
||||||
Address common.Address `json:"address"`
|
Address common.Address `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a Account) String() string {
|
||||||
|
s, err := json.Marshal(a)
|
||||||
|
if err == nil {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
// TransactionArg represents a transaction for the signer.
|
// TransactionArg represents a transaction for the signer.
|
||||||
type TransactionArg struct {
|
type TransactionArg struct {
|
||||||
To *common.Address `json:"to"`
|
To *common.Address `json:"to"`
|
||||||
|
|
@ -37,3 +57,11 @@ type TransactionArg struct {
|
||||||
Data hexutil.Bytes `json:"data"`
|
Data hexutil.Bytes `json:"data"`
|
||||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t TransactionArg) String() string {
|
||||||
|
s, err := json.Marshal(t)
|
||||||
|
if err == nil {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue