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 */