github.com/xfond/eth-implementation@v1.8.9-0.20180514135602-f6bc65fc6811/signer/core/api_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  //
    17  package core
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"math/big"
    25  	"os"
    26  	"path/filepath"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/ethereum/go-ethereum/accounts/keystore"
    31  	"github.com/ethereum/go-ethereum/cmd/utils"
    32  	"github.com/ethereum/go-ethereum/common"
    33  	"github.com/ethereum/go-ethereum/common/hexutil"
    34  	"github.com/ethereum/go-ethereum/core/types"
    35  	"github.com/ethereum/go-ethereum/internal/ethapi"
    36  	"github.com/ethereum/go-ethereum/rlp"
    37  )
    38  
    39  //Used for testing
    40  type HeadlessUI struct {
    41  	controller chan string
    42  }
    43  
    44  func (ui *HeadlessUI) OnSignerStartup(info StartupInfo) {
    45  }
    46  
    47  func (ui *HeadlessUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
    48  	fmt.Printf("OnApproved called")
    49  }
    50  
    51  func (ui *HeadlessUI) ApproveTx(request *SignTxRequest) (SignTxResponse, error) {
    52  
    53  	switch <-ui.controller {
    54  	case "Y":
    55  		return SignTxResponse{request.Transaction, true, <-ui.controller}, nil
    56  	case "M": //Modify
    57  		old := big.Int(request.Transaction.Value)
    58  		newVal := big.NewInt(0).Add(&old, big.NewInt(1))
    59  		request.Transaction.Value = hexutil.Big(*newVal)
    60  		return SignTxResponse{request.Transaction, true, <-ui.controller}, nil
    61  	default:
    62  		return SignTxResponse{request.Transaction, false, ""}, nil
    63  	}
    64  }
    65  func (ui *HeadlessUI) ApproveSignData(request *SignDataRequest) (SignDataResponse, error) {
    66  	if "Y" == <-ui.controller {
    67  		return SignDataResponse{true, <-ui.controller}, nil
    68  	}
    69  	return SignDataResponse{false, ""}, nil
    70  }
    71  func (ui *HeadlessUI) ApproveExport(request *ExportRequest) (ExportResponse, error) {
    72  
    73  	return ExportResponse{<-ui.controller == "Y"}, nil
    74  
    75  }
    76  func (ui *HeadlessUI) ApproveImport(request *ImportRequest) (ImportResponse, error) {
    77  
    78  	if "Y" == <-ui.controller {
    79  		return ImportResponse{true, <-ui.controller, <-ui.controller}, nil
    80  	}
    81  	return ImportResponse{false, "", ""}, nil
    82  }
    83  func (ui *HeadlessUI) ApproveListing(request *ListRequest) (ListResponse, error) {
    84  
    85  	switch <-ui.controller {
    86  	case "A":
    87  		return ListResponse{request.Accounts}, nil
    88  	case "1":
    89  		l := make([]Account, 1)
    90  		l[0] = request.Accounts[1]
    91  		return ListResponse{l}, nil
    92  	default:
    93  		return ListResponse{nil}, nil
    94  	}
    95  }
    96  func (ui *HeadlessUI) ApproveNewAccount(request *NewAccountRequest) (NewAccountResponse, error) {
    97  
    98  	if "Y" == <-ui.controller {
    99  		return NewAccountResponse{true, <-ui.controller}, nil
   100  	}
   101  	return NewAccountResponse{false, ""}, nil
   102  }
   103  func (ui *HeadlessUI) ShowError(message string) {
   104  	//stdout is used by communication
   105  	fmt.Fprint(os.Stderr, message)
   106  }
   107  func (ui *HeadlessUI) ShowInfo(message string) {
   108  	//stdout is used by communication
   109  	fmt.Fprint(os.Stderr, message)
   110  }
   111  
   112  func tmpDirName(t *testing.T) string {
   113  	d, err := ioutil.TempDir("", "eth-keystore-test")
   114  	if err != nil {
   115  		t.Fatal(err)
   116  	}
   117  	d, err = filepath.EvalSymlinks(d)
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	return d
   122  }
   123  
   124  func setup(t *testing.T) (*SignerAPI, chan string) {
   125  
   126  	controller := make(chan string, 10)
   127  
   128  	db, err := NewAbiDBFromFile("../../cmd/clef/4byte.json")
   129  	if err != nil {
   130  		utils.Fatalf(err.Error())
   131  	}
   132  	var (
   133  		ui  = &HeadlessUI{controller}
   134  		api = NewSignerAPI(
   135  			1,
   136  			tmpDirName(t),
   137  			true,
   138  			ui,
   139  			db,
   140  			true)
   141  	)
   142  	return api, controller
   143  }
   144  func createAccount(control chan string, api *SignerAPI, t *testing.T) {
   145  
   146  	control <- "Y"
   147  	control <- "apassword"
   148  	_, err := api.New(context.Background())
   149  	if err != nil {
   150  		t.Fatal(err)
   151  	}
   152  	// Some time to allow changes to propagate
   153  	time.Sleep(250 * time.Millisecond)
   154  }
   155  func failCreateAccount(control chan string, api *SignerAPI, t *testing.T) {
   156  	control <- "N"
   157  	acc, err := api.New(context.Background())
   158  	if err != ErrRequestDenied {
   159  		t.Fatal(err)
   160  	}
   161  	if acc.Address != (common.Address{}) {
   162  		t.Fatal("Empty address should be returned")
   163  	}
   164  }
   165  func list(control chan string, api *SignerAPI, t *testing.T) []Account {
   166  	control <- "A"
   167  	list, err := api.List(context.Background())
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	return list
   172  }
   173  
   174  func TestNewAcc(t *testing.T) {
   175  
   176  	api, control := setup(t)
   177  	verifyNum := func(num int) {
   178  		if list := list(control, api, t); len(list) != num {
   179  			t.Errorf("Expected %d accounts, got %d", num, len(list))
   180  		}
   181  	}
   182  	// Testing create and create-deny
   183  	createAccount(control, api, t)
   184  	createAccount(control, api, t)
   185  	failCreateAccount(control, api, t)
   186  	failCreateAccount(control, api, t)
   187  	createAccount(control, api, t)
   188  	failCreateAccount(control, api, t)
   189  	createAccount(control, api, t)
   190  	failCreateAccount(control, api, t)
   191  	verifyNum(4)
   192  
   193  	// Testing listing:
   194  	// Listing one Account
   195  	control <- "1"
   196  	list, err := api.List(context.Background())
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  	if len(list) != 1 {
   201  		t.Fatalf("List should only show one Account")
   202  	}
   203  	// Listing denied
   204  	control <- "Nope"
   205  	list, err = api.List(context.Background())
   206  	if len(list) != 0 {
   207  		t.Fatalf("List should be empty")
   208  	}
   209  	if err != ErrRequestDenied {
   210  		t.Fatal("Expected deny")
   211  	}
   212  }
   213  
   214  func TestSignData(t *testing.T) {
   215  
   216  	api, control := setup(t)
   217  	//Create two accounts
   218  	createAccount(control, api, t)
   219  	createAccount(control, api, t)
   220  	control <- "1"
   221  	list, err := api.List(context.Background())
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  	a := common.NewMixedcaseAddress(list[0].Address)
   226  
   227  	control <- "Y"
   228  	control <- "wrongpassword"
   229  	h, err := api.Sign(context.Background(), a, []byte("EHLO world"))
   230  	if h != nil {
   231  		t.Errorf("Expected nil-data, got %x", h)
   232  	}
   233  	if err != keystore.ErrDecrypt {
   234  		t.Errorf("Expected ErrLocked! %v", err)
   235  	}
   236  
   237  	control <- "No way"
   238  	h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
   239  	if h != nil {
   240  		t.Errorf("Expected nil-data, got %x", h)
   241  	}
   242  	if err != ErrRequestDenied {
   243  		t.Errorf("Expected ErrRequestDenied! %v", err)
   244  	}
   245  
   246  	control <- "Y"
   247  	control <- "apassword"
   248  	h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
   249  
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	if h == nil || len(h) != 65 {
   254  		t.Errorf("Expected 65 byte signature (got %d bytes)", len(h))
   255  	}
   256  }
   257  func mkTestTx(from common.MixedcaseAddress) SendTxArgs {
   258  	to := common.NewMixedcaseAddress(common.HexToAddress("0x1337"))
   259  	gas := hexutil.Uint64(21000)
   260  	gasPrice := (hexutil.Big)(*big.NewInt(2000000000))
   261  	value := (hexutil.Big)(*big.NewInt(1e18))
   262  	nonce := (hexutil.Uint64)(0)
   263  	data := hexutil.Bytes(common.Hex2Bytes("01020304050607080a"))
   264  	tx := SendTxArgs{
   265  		From:     from,
   266  		To:       &to,
   267  		Gas:      gas,
   268  		GasPrice: gasPrice,
   269  		Value:    value,
   270  		Data:     &data,
   271  		Nonce:    nonce}
   272  	return tx
   273  }
   274  
   275  func TestSignTx(t *testing.T) {
   276  
   277  	var (
   278  		list      Accounts
   279  		res, res2 *ethapi.SignTransactionResult
   280  		err       error
   281  	)
   282  
   283  	api, control := setup(t)
   284  	createAccount(control, api, t)
   285  	control <- "A"
   286  	list, err = api.List(context.Background())
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	a := common.NewMixedcaseAddress(list[0].Address)
   291  
   292  	methodSig := "test(uint)"
   293  	tx := mkTestTx(a)
   294  
   295  	control <- "Y"
   296  	control <- "wrongpassword"
   297  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   298  	if res != nil {
   299  		t.Errorf("Expected nil-response, got %v", res)
   300  	}
   301  	if err != keystore.ErrDecrypt {
   302  		t.Errorf("Expected ErrLocked! %v", err)
   303  	}
   304  
   305  	control <- "No way"
   306  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   307  	if res != nil {
   308  		t.Errorf("Expected nil-response, got %v", res)
   309  	}
   310  	if err != ErrRequestDenied {
   311  		t.Errorf("Expected ErrRequestDenied! %v", err)
   312  	}
   313  
   314  	control <- "Y"
   315  	control <- "apassword"
   316  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   317  
   318  	if err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	parsedTx := &types.Transaction{}
   322  	rlp.Decode(bytes.NewReader(res.Raw), parsedTx)
   323  	//The tx should NOT be modified by the UI
   324  	if parsedTx.Value().Cmp(tx.Value.ToInt()) != 0 {
   325  		t.Errorf("Expected value to be unchanged, expected %v got %v", tx.Value, parsedTx.Value())
   326  	}
   327  	control <- "Y"
   328  	control <- "apassword"
   329  
   330  	res2, err = api.SignTransaction(context.Background(), tx, &methodSig)
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	if !bytes.Equal(res.Raw, res2.Raw) {
   335  		t.Error("Expected tx to be unmodified by UI")
   336  	}
   337  
   338  	//The tx is modified by the UI
   339  	control <- "M"
   340  	control <- "apassword"
   341  
   342  	res2, err = api.SignTransaction(context.Background(), tx, &methodSig)
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  
   347  	parsedTx2 := &types.Transaction{}
   348  	rlp.Decode(bytes.NewReader(res.Raw), parsedTx2)
   349  	//The tx should be modified by the UI
   350  	if parsedTx2.Value().Cmp(tx.Value.ToInt()) != 0 {
   351  		t.Errorf("Expected value to be unchanged, got %v", parsedTx.Value())
   352  	}
   353  
   354  	if bytes.Equal(res.Raw, res2.Raw) {
   355  		t.Error("Expected tx to be modified by UI")
   356  	}
   357  
   358  }
   359  
   360  /*
   361  func TestAsyncronousResponses(t *testing.T){
   362  
   363  	//Set up one account
   364  	api, control := setup(t)
   365  	createAccount(control, api, t)
   366  
   367  	// Two transactions, the second one with larger value than the first
   368  	tx1 := mkTestTx()
   369  	newVal := big.NewInt(0).Add((*big.Int) (tx1.Value), big.NewInt(1))
   370  	tx2 := mkTestTx()
   371  	tx2.Value = (*hexutil.Big)(newVal)
   372  
   373  	control <- "W" //wait
   374  	control <- "Y" //
   375  	control <- "apassword"
   376  	control <- "Y" //
   377  	control <- "apassword"
   378  
   379  	var err error
   380  
   381  	h1, err := api.SignTransaction(context.Background(), common.HexToAddress("1111"), tx1, nil)
   382  	h2, err := api.SignTransaction(context.Background(), common.HexToAddress("2222"), tx2, nil)
   383  
   384  
   385  	}
   386  */