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