github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/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/vntchain/go-vnt/accounts/keystore"
    31  	"github.com/vntchain/go-vnt/cmd/utils"
    32  	"github.com/vntchain/go-vnt/common"
    33  	"github.com/vntchain/go-vnt/common/hexutil"
    34  	"github.com/vntchain/go-vnt/core/types"
    35  	"github.com/vntchain/go-vnt/internal/vntapi"
    36  	"github.com/vntchain/go-vnt/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 vntapi.SignTransactionResult) {
    48  	fmt.Printf("OnApproved called\n")
    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("", "vnt-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  			ui,
   138  			db,
   139  			true)
   140  	)
   141  	return api, controller
   142  }
   143  func createAccount(control chan string, api *SignerAPI, t *testing.T) {
   144  
   145  	control <- "Y"
   146  	control <- "apassword"
   147  	_, err := api.New(context.Background())
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  	// Some time to allow changes to propagate
   152  	time.Sleep(250 * time.Millisecond)
   153  }
   154  func failCreateAccount(control chan string, api *SignerAPI, t *testing.T) {
   155  	control <- "N"
   156  	acc, err := api.New(context.Background())
   157  	if err != ErrRequestDenied {
   158  		t.Fatal(err)
   159  	}
   160  	if acc.Address != (common.Address{}) {
   161  		t.Fatal("Empty address should be returned")
   162  	}
   163  }
   164  func list(control chan string, api *SignerAPI, t *testing.T) []Account {
   165  	control <- "A"
   166  	list, err := api.List(context.Background())
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	return list
   171  }
   172  
   173  func TestNewAcc(t *testing.T) {
   174  
   175  	api, control := setup(t)
   176  	verifyNum := func(num int) {
   177  		if list := list(control, api, t); len(list) != num {
   178  			t.Errorf("Expected %d accounts, got %d", num, len(list))
   179  		}
   180  	}
   181  	// Testing create and create-deny
   182  	createAccount(control, api, t)
   183  	createAccount(control, api, t)
   184  	failCreateAccount(control, api, t)
   185  	failCreateAccount(control, api, t)
   186  	createAccount(control, api, t)
   187  	failCreateAccount(control, api, t)
   188  	createAccount(control, api, t)
   189  	failCreateAccount(control, api, t)
   190  	verifyNum(4)
   191  
   192  	// Testing listing:
   193  	// Listing one Account
   194  	control <- "1"
   195  	list, err := api.List(context.Background())
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	if len(list) != 1 {
   200  		t.Fatalf("List should only show one Account")
   201  	}
   202  	// Listing denied
   203  	control <- "Nope"
   204  	list, err = api.List(context.Background())
   205  	if len(list) != 0 {
   206  		t.Fatalf("List should be empty")
   207  	}
   208  	if err != ErrRequestDenied {
   209  		t.Fatal("Expected deny")
   210  	}
   211  }
   212  
   213  func TestSignData(t *testing.T) {
   214  	api, control := setup(t)
   215  	//Create two accounts
   216  	createAccount(control, api, t)
   217  	createAccount(control, api, t)
   218  	control <- "1"
   219  	list, err := api.List(context.Background())
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  	a := common.NewMixedcaseAddress(list[0].Address)
   224  
   225  	control <- "Y"
   226  	control <- "wrongpassword"
   227  	h, err := api.Sign(context.Background(), a, []byte("EHLO world"))
   228  	if h != nil {
   229  		t.Errorf("Expected nil-data, got %x", h)
   230  	}
   231  	if err != keystore.ErrDecrypt {
   232  		t.Errorf("Expected ErrLocked! %v", err)
   233  	}
   234  	fmt.Println()
   235  
   236  	control <- "No way"
   237  	h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
   238  	if h != nil {
   239  		t.Errorf("Expected nil-data, got %x", h)
   240  	}
   241  	if err != ErrRequestDenied {
   242  		t.Errorf("Expected ErrRequestDenied! %v", err)
   243  	}
   244  
   245  	control <- "Y"
   246  	control <- "apassword"
   247  	h, err = api.Sign(context.Background(), a, []byte("EHLO world"))
   248  
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	if h == nil || len(h) != 65 {
   253  		t.Errorf("Expected 65 byte signature (got %d bytes)", len(h))
   254  	}
   255  }
   256  func mkTestTx(from common.MixedcaseAddress) SendTxArgs {
   257  	to := common.NewMixedcaseAddress(common.HexToAddress("0x1337"))
   258  	gas := hexutil.Uint64(21000)
   259  	gasPrice := (hexutil.Big)(*big.NewInt(2000000000))
   260  	value := (hexutil.Big)(*big.NewInt(1e18))
   261  	nonce := (hexutil.Uint64)(0)
   262  	data := hexutil.Bytes(common.Hex2Bytes("01020304050607080a"))
   263  	tx := SendTxArgs{
   264  		From:     from,
   265  		To:       &to,
   266  		Gas:      gas,
   267  		GasPrice: gasPrice,
   268  		Value:    value,
   269  		Data:     &data,
   270  		Nonce:    nonce}
   271  	return tx
   272  }
   273  
   274  func TestSignTx(t *testing.T) {
   275  
   276  	var (
   277  		list      Accounts
   278  		res, res2 *vntapi.SignTransactionResult
   279  		err       error
   280  	)
   281  
   282  	api, control := setup(t)
   283  	createAccount(control, api, t)
   284  	control <- "A"
   285  	list, err = api.List(context.Background())
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  	a := common.NewMixedcaseAddress(list[0].Address)
   290  
   291  	methodSig := "test(uint)"
   292  	tx := mkTestTx(a)
   293  
   294  	control <- "Y"
   295  	control <- "wrongpassword"
   296  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   297  	if res != nil {
   298  		t.Errorf("Expected nil-response, got %v", res)
   299  	}
   300  	if err != keystore.ErrDecrypt {
   301  		t.Errorf("Expected ErrLocked! %v", err)
   302  	}
   303  
   304  	control <- "No way"
   305  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   306  	if res != nil {
   307  		t.Errorf("Expected nil-response, got %v", res)
   308  	}
   309  	if err != ErrRequestDenied {
   310  		t.Errorf("Expected ErrRequestDenied! %v", err)
   311  	}
   312  
   313  	control <- "Y"
   314  	control <- "apassword"
   315  	res, err = api.SignTransaction(context.Background(), tx, &methodSig)
   316  
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  	parsedTx := &types.Transaction{}
   321  	rlp.Decode(bytes.NewReader(res.Raw), parsedTx)
   322  	//The tx should NOT be modified by the UI
   323  	if parsedTx.Value().Cmp(tx.Value.ToInt()) != 0 {
   324  		t.Errorf("Expected value to be unchanged, expected %v got %v", tx.Value, parsedTx.Value())
   325  	}
   326  	control <- "Y"
   327  	control <- "apassword"
   328  
   329  	res2, err = api.SignTransaction(context.Background(), tx, &methodSig)
   330  	if err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	if !bytes.Equal(res.Raw, res2.Raw) {
   334  		t.Error("Expected tx to be unmodified by UI")
   335  	}
   336  
   337  	//The tx is modified by the UI
   338  	control <- "M"
   339  	control <- "apassword"
   340  
   341  	res2, err = api.SignTransaction(context.Background(), tx, &methodSig)
   342  	if err != nil {
   343  		t.Fatal(err)
   344  	}
   345  
   346  	parsedTx2 := &types.Transaction{}
   347  	rlp.Decode(bytes.NewReader(res.Raw), parsedTx2)
   348  	//The tx should be modified by the UI
   349  	if parsedTx2.Value().Cmp(tx.Value.ToInt()) != 0 {
   350  		t.Errorf("Expected value to be unchanged, got %v", parsedTx.Value())
   351  	}
   352  
   353  	if bytes.Equal(res.Raw, res2.Raw) {
   354  		t.Error("Expected tx to be modified by UI")
   355  	}
   356  
   357  }
   358  
   359  /*
   360  func TestAsyncronousResponses(t *testing.T){
   361  
   362  	//Set up one account
   363  	api, control := setup(t)
   364  	createAccount(control, api, t)
   365  
   366  	// Two transactions, the second one with larger value than the first
   367  	tx1 := mkTestTx()
   368  	newVal := big.NewInt(0).Add((*big.Int) (tx1.Value), big.NewInt(1))
   369  	tx2 := mkTestTx()
   370  	tx2.Value = (*hexutil.Big)(newVal)
   371  
   372  	control <- "W" //wait
   373  	control <- "Y" //
   374  	control <- "apassword"
   375  	control <- "Y" //
   376  	control <- "apassword"
   377  
   378  	var err error
   379  
   380  	h1, err := api.SignTransaction(context.Background(), common.HexToAddress("1111"), tx1, nil)
   381  	h2, err := api.SignTransaction(context.Background(), common.HexToAddress("2222"), tx2, nil)
   382  
   383  
   384  	}
   385  */