github.com/klaytn/klaytn@v1.12.1/cmd/utils/nodecmd/accountcmd_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2016 The go-ethereum Authors 3 // This file is part of go-ethereum. 4 // 5 // go-ethereum is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // go-ethereum is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from cmd/geth/accountcmd_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package nodecmd 22 23 import ( 24 "fmt" 25 "os" 26 "path/filepath" 27 "runtime" 28 "strings" 29 "testing" 30 "time" 31 32 "github.com/cespare/cp" 33 "github.com/stretchr/testify/assert" 34 ) 35 36 // These tests are 'smoke tests' for the account related 37 // subcommands and flags. 38 // 39 // For most tests, the test files from package accounts 40 // are copied into a temporary keystore directory. 41 42 func tmpDatadirWithKeystore(t *testing.T) string { 43 datadir := tmpdir(t) 44 keystore := filepath.Join(datadir, "keystore") 45 source := filepath.Join("..", "..", "..", "accounts", "keystore", "testdata", "keystore") 46 if err := cp.CopyAll(keystore, source); err != nil { 47 t.Fatal(err) 48 } 49 return datadir 50 } 51 52 func TestAccountListEmpty(t *testing.T) { 53 klay := runKlay(t, "klay-test", "account", "list") 54 klay.ExpectExit() 55 } 56 57 func TestAccountList(t *testing.T) { 58 datadir := tmpDatadirWithKeystore(t) 59 klay := runKlay(t, "klay-test", "account", "list", "--datadir", datadir) 60 defer klay.ExpectExit() 61 if runtime.GOOS == "windows" { 62 klay.Expect(` 63 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}\keystore\UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 64 Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}\keystore\aaa 65 Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}\keystore\zzz 66 `) 67 } else { 68 klay.Expect(` 69 Account #0: {7ef5a6135f1fd6a02593eedc869c6d41d934aef8} keystore://{{.Datadir}}/keystore/UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8 70 Account #1: {f466859ead1932d743d622cb74fc058882e8648a} keystore://{{.Datadir}}/keystore/aaa 71 Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/keystore/zzz 72 `) 73 } 74 } 75 76 func TestAccountNew(t *testing.T) { 77 klay := runKlay(t, "klay-test", "account", "new", "--lightkdf") 78 defer klay.ExpectExit() 79 klay.Expect(` 80 Your new account is locked with a password. Please give a password. Do not forget this password. 81 !! Unsupported terminal, password will be echoed. 82 Passphrase: {{.InputLine "foobar"}} 83 Repeat passphrase: {{.InputLine "foobar"}} 84 `) 85 klay.ExpectRegexp(`Address: \{[0-9a-f]{40}\}\n`) 86 } 87 88 func TestAccountNewBadRepeat(t *testing.T) { 89 klay := runKlay(t, "klay-test", "account", "new", "--lightkdf") 90 defer klay.ExpectExit() 91 klay.Expect(` 92 Your new account is locked with a password. Please give a password. Do not forget this password. 93 !! Unsupported terminal, password will be echoed. 94 Passphrase: {{.InputLine "something"}} 95 Repeat passphrase: {{.InputLine "something else"}} 96 Fatal: Passphrases do not match 97 `) 98 } 99 100 func TestAccountUpdate(t *testing.T) { 101 datadir := tmpDatadirWithKeystore(t) 102 klay := runKlay(t, "klay-test", "account", "update", 103 "--datadir", datadir, "--lightkdf", 104 "f466859ead1932d743d622cb74fc058882e8648a") 105 defer klay.ExpectExit() 106 klay.Expect(` 107 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 108 !! Unsupported terminal, password will be echoed. 109 Passphrase: {{.InputLine "foobar"}} 110 Please give a new password. Do not forget this password. 111 Passphrase: {{.InputLine "foobar2"}} 112 Repeat passphrase: {{.InputLine "foobar2"}} 113 `) 114 } 115 116 func TestUnlockFlag(t *testing.T) { 117 datadir := tmpDatadirWithKeystore(t) 118 klay := runKlay(t, "klay-test", 119 "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 120 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", 121 "js", "testdata/empty.js") 122 klay.Expect(` 123 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 124 !! Unsupported terminal, password will be echoed. 125 Passphrase: {{.InputLine "foobar"}} 126 `) 127 klay.ExpectExit() 128 129 wantMessages := []string{ 130 "Unlocked account", 131 "0xf466859eAD1932D743d622CB74FC058882E8648A", 132 } 133 for _, m := range wantMessages { 134 if !strings.Contains(klay.StderrText(), m) { 135 t.Errorf("stderr text does not contain %q", m) 136 } 137 } 138 } 139 140 func TestUnlockFlagWrongPassword(t *testing.T) { 141 datadir := tmpDatadirWithKeystore(t) 142 klay := runKlay(t, "klay-test", 143 "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 144 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a") 145 defer klay.ExpectExit() 146 klay.Expect(` 147 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 148 !! Unsupported terminal, password will be echoed. 149 Passphrase: {{.InputLine "wrong1"}} 150 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 2/3 151 Passphrase: {{.InputLine "wrong2"}} 152 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 3/3 153 Passphrase: {{.InputLine "wrong3"}} 154 Fatal: Failed to unlock account f466859ead1932d743d622cb74fc058882e8648a (could not decrypt key with given passphrase) 155 `) 156 } 157 158 // https://github.com/ethereum/go-ethereum/issues/1785 159 func TestUnlockFlagMultiIndex(t *testing.T) { 160 datadir := tmpDatadirWithKeystore(t) 161 klay := runKlay(t, "klay-test", 162 "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 163 "--unlock", "0,2", 164 "js", "testdata/empty.js") 165 klay.Expect(` 166 Unlocking account 0 | Attempt 1/3 167 !! Unsupported terminal, password will be echoed. 168 Passphrase: {{.InputLine "foobar"}} 169 Unlocking account 2 | Attempt 1/3 170 Passphrase: {{.InputLine "foobar"}} 171 `) 172 klay.ExpectExit() 173 174 wantMessages := []string{ 175 "Unlocked account", 176 "0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", 177 "0x289d485D9771714CCe91D3393D764E1311907ACc", 178 } 179 for _, m := range wantMessages { 180 if !strings.Contains(klay.StderrText(), m) { 181 t.Errorf("stderr text does not contain %q", m) 182 } 183 } 184 } 185 186 func TestUnlockFlagPasswordFile(t *testing.T) { 187 datadir := tmpDatadirWithKeystore(t) 188 klay := runKlay(t, "klay-test", 189 "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 190 "--password", "testdata/passwords.txt", "--unlock", "0,2", 191 "js", "testdata/empty.js") 192 klay.ExpectExit() 193 194 wantMessages := []string{ 195 "Unlocked account", 196 "0x7EF5A6135f1FD6a02593eEdC869c6D41D934aef8", 197 "0x289d485D9771714CCe91D3393D764E1311907ACc", 198 } 199 for _, m := range wantMessages { 200 if !strings.Contains(klay.StderrText(), m) { 201 t.Errorf("stderr text does not contain %q", m) 202 } 203 } 204 } 205 206 func TestUnlockFlagPasswordFileWrongPassword(t *testing.T) { 207 datadir := tmpDatadirWithKeystore(t) 208 klay := runKlay(t, "klay-test", 209 "--datadir", datadir, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 210 "--password", "testdata/wrong-passwords.txt", "--unlock", "0,2") 211 defer klay.ExpectExit() 212 klay.Expect(` 213 Fatal: Failed to unlock account 0 (could not decrypt key with given passphrase) 214 `) 215 } 216 217 func TestUnlockFlagAmbiguous(t *testing.T) { 218 store := filepath.Join("..", "..", "..", "accounts", "keystore", "testdata", "dupes") 219 klay := runKlay(t, "klay-test", 220 "--keystore", store, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 221 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a", 222 "js", "testdata/empty.js") 223 defer klay.ExpectExit() 224 225 // Helper for the expect template, returns absolute keystore path. 226 klay.SetTemplateFunc("keypath", func(file string) string { 227 abs, _ := filepath.Abs(filepath.Join(store, file)) 228 return abs 229 }) 230 klay.Expect(` 231 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 232 !! Unsupported terminal, password will be echoed. 233 Passphrase: {{.InputLine "foobar"}} 234 Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: 235 keystore://{{keypath "1"}} 236 keystore://{{keypath "2"}} 237 Testing your passphrase against all of them... 238 Your passphrase unlocked keystore://{{keypath "1"}} 239 In order to avoid this warning, you need to remove the following duplicate key files: 240 keystore://{{keypath "2"}} 241 `) 242 klay.ExpectExit() 243 244 wantMessages := []string{ 245 "Unlocked account", 246 "0xf466859eAD1932D743d622CB74FC058882E8648A", 247 } 248 for _, m := range wantMessages { 249 if !strings.Contains(klay.StderrText(), m) { 250 t.Errorf("stderr text does not contain %q", m) 251 } 252 } 253 } 254 255 func TestUnlockFlagAmbiguousWrongPassword(t *testing.T) { 256 store := filepath.Join("..", "..", "..", "accounts", "keystore", "testdata", "dupes") 257 klay := runKlay(t, "klay-test", 258 "--keystore", store, "--nat", "none", "--nodiscover", "--maxconnections", "0", "--port", "0", 259 "--unlock", "f466859ead1932d743d622cb74fc058882e8648a") 260 defer klay.ExpectExit() 261 262 // Helper for the expect template, returns absolute keystore path. 263 klay.SetTemplateFunc("keypath", func(file string) string { 264 abs, _ := filepath.Abs(filepath.Join(store, file)) 265 return abs 266 }) 267 klay.Expect(` 268 Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3 269 !! Unsupported terminal, password will be echoed. 270 Passphrase: {{.InputLine "wrong"}} 271 Multiple key files exist for address f466859ead1932d743d622cb74fc058882e8648a: 272 keystore://{{keypath "1"}} 273 keystore://{{keypath "2"}} 274 Testing your passphrase against all of them... 275 Fatal: None of the listed files could be unlocked. 276 `) 277 klay.ExpectExit() 278 } 279 280 func TestBlsInfo(t *testing.T) { 281 // Test datadir/nodekey -> bls-publicinfo.json 282 var ( 283 datadir = tmpdir(t) 284 nodekeyPath = filepath.Join(datadir, "klay", "nodekey") 285 nodekeyHex = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" 286 287 outputPath = "bls-publicinfo-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266.json" 288 expectPrint = `Successfully wrote 'bls-publicinfo-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266.json'` 289 expectFile = `{ 290 "address": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 291 "blsPublicKeyInfo": { 292 "publicKey": "876006073c4ef19d23df948fea3e7e95398d6a7b5acc6a510f24e2d5160bbbd9f636a58cdfe69c8eba42b1cfce0fa60a", 293 "pop": "ac7886654439a16c53be123d1956bb1bfe4a04b118ac50d9d4a56aef8a8e1e23128a8d720a9290a4dfa411df2384f5dc0bf9ee9861846fe1bd3f0fbd998935deda91cb28ceefe5ff8f307b43c0559dfbc96d7f2b6361980edb0298f28479908e" 294 } 295 }` 296 ) 297 defer os.RemoveAll(datadir) 298 defer os.Remove(outputPath) 299 t.Logf("datadir: %s", datadir) 300 301 // Save nodekey before node starts 302 assert.Nil(t, os.MkdirAll(filepath.Join(datadir, "klay"), 0o700)) 303 assert.Nil(t, os.WriteFile(nodekeyPath, []byte(nodekeyHex), 0o400)) 304 server := runKlay(t, "klay-test", "--datadir", datadir, 305 "--netrestrict", "127.0.0.1/32", "--port", "0", "--verbosity", "2") 306 time.Sleep(5 * time.Second) // Simple way to wait for the RPC endpoint to open 307 308 os.Remove(outputPath) // delete before test, because otherwise the "already exists" error occurs 309 client := runKlay(t, "klay-test", "account", "bls-info", "--datadir", datadir) 310 client.ExpectRegexp(expectPrint) 311 312 content, err := os.ReadFile(outputPath) 313 assert.Nil(t, err) 314 assert.JSONEq(t, expectFile, string(content)) 315 316 server.Interrupt() 317 server.ExpectExit() 318 } 319 320 func TestBlsImport(t *testing.T) { 321 // Test keystore + password -> datadir/bls-nodekey 322 var ( 323 // Scrypt Test Vector from https://eips.ethereum.org/EIPS/eip-2335 324 keystorePath = "../../../accounts/keystore/testdata/eip2335_scrypt.json" 325 passwordPath = "../../../accounts/keystore/testdata/eip2335_password.txt" 326 327 datadir = tmpdir(t) 328 outputPath = filepath.Join(datadir, "klay", "bls-nodekey") 329 expectPrint = fmt.Sprintf( 330 "Importing BLS key: pub=9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07\n"+ 331 "Successfully wrote '%s/klay/bls-nodekey'", datadir) 332 expectFile = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" 333 ) 334 defer os.RemoveAll(datadir) 335 t.Logf("datadir: %s", datadir) 336 337 klay := runKlay(t, "klay-test", "account", "bls-import", "--datadir", datadir, 338 "--bls-nodekeystore", keystorePath, "--password", passwordPath) 339 klay.ExpectRegexp(expectPrint) 340 341 content, err := os.ReadFile(outputPath) 342 assert.Nil(t, err) 343 assert.Regexp(t, expectFile, string(content)) 344 } 345 346 func TestBlsExport(t *testing.T) { 347 // Test datadir/bls-nodekey -> bls-keystore.json 348 var ( 349 datadir = tmpdir(t) 350 nodekeyPath = filepath.Join(datadir, "klay", "nodekey") 351 nodekeyHex = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" 352 blsnodekeyPath = filepath.Join(datadir, "klay", "bls-nodekey") 353 blsnodekeyHex = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f" 354 355 outputPath = "bls-keystore-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266.json" 356 expectPrint = `Successfully wrote 'bls-keystore-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266.json'` 357 expectFile = []string{ 358 `"pubkey":"9612d7a727c9d0a22e185a1c768478dfe919cada9266988cb32359c11f2b7b27f4ae4040902382ae2910c15e2b420d07"`, 359 `"path":""`, 360 `"version":4`, 361 } 362 ) 363 defer os.RemoveAll(datadir) 364 defer os.Remove(outputPath) 365 t.Logf("datadir: %s", datadir) 366 367 assert.Nil(t, os.MkdirAll(filepath.Join(datadir, "klay"), 0o700)) 368 assert.Nil(t, os.WriteFile(nodekeyPath, []byte(nodekeyHex), 0o400)) 369 assert.Nil(t, os.WriteFile(blsnodekeyPath, []byte(blsnodekeyHex), 0o400)) 370 371 os.Remove(outputPath) // delete before test, because otherwise the "already exists" error occurs 372 klay := runKlay(t, "klay-test", "account", "bls-export", "--datadir", datadir) 373 klay.InputLine("1234") // Enter password 374 klay.InputLine("1234") // Confirm password 375 klay.ExpectRegexp(expectPrint) 376 377 content, err := os.ReadFile(outputPath) 378 assert.Nil(t, err) 379 for _, expectField := range expectFile { 380 assert.Regexp(t, expectField, string(content)) 381 } 382 }