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  }