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