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