code.vegaprotocol.io/vega@v0.79.0/wallet/wallets/handler_test.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package wallets_test
    17  
    18  import (
    19  	"fmt"
    20  	"testing"
    21  
    22  	vgrand "code.vegaprotocol.io/vega/libs/rand"
    23  	commandspb "code.vegaprotocol.io/vega/protos/vega/commands/v1"
    24  	walletpb "code.vegaprotocol.io/vega/protos/vega/wallet/v1"
    25  	"code.vegaprotocol.io/vega/wallet/wallet"
    26  	"code.vegaprotocol.io/vega/wallet/wallets"
    27  
    28  	"github.com/golang/mock/gomock"
    29  	"github.com/stretchr/testify/assert"
    30  	"github.com/stretchr/testify/require"
    31  )
    32  
    33  const (
    34  	TestRecoveryPhrase1 = "swing ceiling chaos green put insane ripple desk match tip melt usual shrug turkey renew icon parade veteran lens govern path rough page render"
    35  	TestRecoveryPhrase2 = "green put insane ripple desk match tip melt usual shrug turkey renew icon parade veteran lens govern path rough page render swing ceiling chaos"
    36  )
    37  
    38  type testHandler struct {
    39  	*wallets.Handler
    40  	ctrl  *gomock.Controller
    41  	store *mockedStore
    42  }
    43  
    44  func getTestHandler(t *testing.T) *testHandler {
    45  	t.Helper()
    46  	ctrl := gomock.NewController(t)
    47  	store := newMockedStore()
    48  	h := wallets.NewHandler(store)
    49  	return &testHandler{
    50  		Handler: h,
    51  		ctrl:    ctrl,
    52  		store:   store,
    53  	}
    54  }
    55  
    56  func TestHandler(t *testing.T) {
    57  	t.Run("Creating a wallet succeeds", testHandlerCreatingWalletSucceeds)
    58  	t.Run("Creating an already existing wallet fails", testHandlerCreatingAlreadyExistingWalletFails)
    59  	t.Run("Importing a wallet succeeds", testHandlerImportingWalletSucceeds)
    60  	t.Run("Importing a wallet with invalid recovery phrase fails", testHandlerImportingWalletWithInvalidRecoveryPhraseFails)
    61  	t.Run("Importing an already existing wallet fails", testHandlerImportingAlreadyExistingWalletFails)
    62  	t.Run("Verifying wallet existence succeeds", testHandlerVerifyingWalletExistenceSucceeds)
    63  	t.Run("Verifying wallet non existence succeeds", testHandlerVerifyingWalletNonExistenceSucceeds)
    64  	t.Run("Recreating a wallet with same name fails", testHandlerRecreatingWalletWithSameNameFails)
    65  	t.Run("Recreating a wallet with same name and different passphrase fails", testHandlerRecreatingWalletWithSameNameButDifferentPassphraseFails)
    66  	t.Run("Login to existing wallet succeeds", testHandlerLoginToExistingWalletSucceeds)
    67  	t.Run("Login to non-existing wallet fails", testHandlerLoginToNonExistingWalletFails)
    68  	t.Run("Generating new key pair securely succeeds", testHandlerGeneratingNewKeyPairSecurelySucceeds)
    69  	t.Run("Generating new key pair securely with invalid name fails", testHandlerGeneratingNewKeyPairSecurelyWithInvalidNameFails)
    70  	t.Run("Generating new key pair securely without wallet fails", testHandlerGeneratingNewKeyPairSecurelyWithoutWalletFails)
    71  	t.Run("Generating new key pair succeeds", testHandlerGeneratingNewKeyPairSucceeds)
    72  	t.Run("Generating new key pair with custom name succeeds", testHandlerGeneratingNewKeyPairWithCustomNameSucceeds)
    73  	t.Run("Generating new key pair with invalid name fails", testHandlerGeneratingNewKeyPairWithInvalidNameFails)
    74  	t.Run("Generating new key pair without wallet fails", testHandlerGeneratingNewKeyPairWithoutWalletFails)
    75  	t.Run("Listing public keys succeeds", testHandlerListingPublicKeysSucceeds)
    76  	t.Run("Listing public keys with invalid name fails", testHandlerListingPublicKeysWithInvalidNameFails)
    77  	t.Run("Listing public keys without wallet fails", testHandlerListingPublicKeysWithoutWalletFails)
    78  	t.Run("Listing key pairs succeeds", testHandlerListingKeyPairsSucceeds)
    79  	t.Run("Listing key pairs with invalid name fails", testHandlerListingKeyPairsWithInvalidNameFails)
    80  	t.Run("Listing key pairs without wallet fails", testHandlerListingKeyPairsWithoutWalletFails)
    81  	t.Run("Getting public key succeeds", testHandlerGettingPublicKeySucceeds)
    82  	t.Run("Getting public key without wallet fails", testHandlerGettingPublicKeyWithoutWalletFails)
    83  	t.Run("Getting public key with invalid name fails", testHandlerGettingPublicKeyWithInvalidNameFails)
    84  	t.Run("Getting non-existing public key fails", testGettingNonExistingPublicKeyFails)
    85  	t.Run("Tainting key pair succeeds", testHandlerTaintingKeyPairSucceeds)
    86  	t.Run("Tainting key pair with invalid name fails", testHandlerTaintingKeyPairWithInvalidNameFails)
    87  	t.Run("Tainting key pair without wallet fails", testHandlerTaintingKeyPairWithoutWalletFails)
    88  	t.Run("Tainting key pair that is already tainted fails", testHandlerTaintingKeyThatIsAlreadyTaintedFails)
    89  	t.Run("Updating key pair metadata succeeds", testHandlerUpdatingKeyPairMetaSucceeds)
    90  	t.Run("Updating key pair metadata with invalid passphrase fails", testHandlerUpdatingKeyPairMetaWithInvalidPassphraseFails)
    91  	t.Run("Updating key pair metadata with invalid name fails", testHandlerUpdatingKeyPairMetaWithInvalidNameFails)
    92  	t.Run("Updating key pair metadata without wallet fails", testHandlerUpdatingKeyPairMetaWithoutWalletFails)
    93  	t.Run("Updating key pair metadata with non-existing public key fails", testHandlerUpdatingKeyPairMetaWithNonExistingPublicKeyFails)
    94  	t.Run("Get wallet path succeeds", testHandlerGettingWalletPathSucceeds)
    95  	t.Run("Signing transaction request succeeds", testHandlerSigningTxSucceeds)
    96  	t.Run("Signing transaction request with tainted key fails", testHandlerSigningTxWithTaintedKeyFails)
    97  	t.Run("Signing and verifying a message succeeds", testHandlerSigningAndVerifyingMessageSucceeds)
    98  }
    99  
   100  func testHandlerCreatingWalletSucceeds(t *testing.T) {
   101  	h := getTestHandler(t)
   102  	defer h.ctrl.Finish()
   103  
   104  	// given
   105  	name := vgrand.RandomStr(5)
   106  	passphrase := vgrand.RandomStr(5)
   107  
   108  	// when
   109  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   110  
   111  	// then
   112  	require.NoError(t, err)
   113  	assert.NotEmpty(t, recoveryPhrase)
   114  }
   115  
   116  func testHandlerCreatingAlreadyExistingWalletFails(t *testing.T) {
   117  	h := getTestHandler(t)
   118  	defer h.ctrl.Finish()
   119  
   120  	// given
   121  	name := vgrand.RandomStr(5)
   122  	passphrase := vgrand.RandomStr(5)
   123  
   124  	// when
   125  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   126  
   127  	// then
   128  	require.NoError(t, err)
   129  	assert.NotEmpty(t, recoveryPhrase)
   130  
   131  	// when
   132  	recoveryPhrase, err = h.CreateWallet(name, passphrase)
   133  
   134  	// then
   135  	require.Error(t, err, wallet.ErrWalletAlreadyExists)
   136  	assert.Empty(t, recoveryPhrase)
   137  }
   138  
   139  func testHandlerImportingWalletSucceeds(t *testing.T) {
   140  	tcs := []struct {
   141  		name    string
   142  		version uint32
   143  	}{
   144  		{
   145  			name:    "version 1",
   146  			version: 1,
   147  		}, {
   148  			name:    "version 2",
   149  			version: 2,
   150  		},
   151  	}
   152  
   153  	for _, tc := range tcs {
   154  		t.Run(tc.name, func(tt *testing.T) {
   155  			h := getTestHandler(t)
   156  			defer h.ctrl.Finish()
   157  
   158  			// given
   159  			name := vgrand.RandomStr(5)
   160  			passphrase := vgrand.RandomStr(5)
   161  
   162  			// when
   163  			err := h.ImportWallet(name, passphrase, TestRecoveryPhrase1, tc.version)
   164  
   165  			// then
   166  			require.NoError(t, err)
   167  		})
   168  	}
   169  }
   170  
   171  func testHandlerImportingWalletWithInvalidRecoveryPhraseFails(t *testing.T) {
   172  	tcs := []struct {
   173  		name    string
   174  		version uint32
   175  	}{
   176  		{
   177  			name:    "version 1",
   178  			version: 1,
   179  		}, {
   180  			name:    "version 2",
   181  			version: 2,
   182  		},
   183  	}
   184  
   185  	for _, tc := range tcs {
   186  		t.Run(tc.name, func(tt *testing.T) {
   187  			h := getTestHandler(t)
   188  			defer h.ctrl.Finish()
   189  
   190  			// given
   191  			name := vgrand.RandomStr(5)
   192  			passphrase := vgrand.RandomStr(5)
   193  
   194  			// when
   195  			err := h.ImportWallet(name, passphrase, "this is not a valid recoveryPhrase", tc.version)
   196  
   197  			// then
   198  			require.ErrorIs(t, err, wallet.ErrInvalidRecoveryPhrase)
   199  		})
   200  	}
   201  }
   202  
   203  func testHandlerImportingAlreadyExistingWalletFails(t *testing.T) {
   204  	tcs := []struct {
   205  		name    string
   206  		version uint32
   207  	}{
   208  		{
   209  			name:    "version 1",
   210  			version: 1,
   211  		}, {
   212  			name:    "version 2",
   213  			version: 2,
   214  		},
   215  	}
   216  	for _, tc := range tcs {
   217  		t.Run(tc.name, func(tt *testing.T) {
   218  			h := getTestHandler(t)
   219  			defer h.ctrl.Finish()
   220  
   221  			// given
   222  			name := vgrand.RandomStr(5)
   223  			passphrase := vgrand.RandomStr(5)
   224  
   225  			// when
   226  			err := h.ImportWallet(name, passphrase, TestRecoveryPhrase1, tc.version)
   227  
   228  			// then
   229  			require.NoError(t, err)
   230  
   231  			// when
   232  			err = h.ImportWallet(name, passphrase, TestRecoveryPhrase2, tc.version)
   233  
   234  			// then
   235  			require.Error(t, err, wallet.ErrWalletAlreadyExists)
   236  		})
   237  	}
   238  }
   239  
   240  func testHandlerVerifyingWalletExistenceSucceeds(t *testing.T) {
   241  	h := getTestHandler(t)
   242  	defer h.ctrl.Finish()
   243  
   244  	// given
   245  	name := vgrand.RandomStr(5)
   246  	passphrase := vgrand.RandomStr(5)
   247  
   248  	// when
   249  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   250  
   251  	// then
   252  	require.NoError(t, err)
   253  	assert.NotEmpty(t, recoveryPhrase)
   254  
   255  	// when
   256  	exists := h.WalletExists(name)
   257  
   258  	// then
   259  	assert.True(t, exists)
   260  }
   261  
   262  func testHandlerVerifyingWalletNonExistenceSucceeds(t *testing.T) {
   263  	h := getTestHandler(t)
   264  	defer h.ctrl.Finish()
   265  
   266  	// given
   267  	name := vgrand.RandomStr(5)
   268  
   269  	// when
   270  	exists := h.WalletExists(name)
   271  
   272  	// then
   273  	assert.False(t, exists)
   274  }
   275  
   276  func testHandlerRecreatingWalletWithSameNameFails(t *testing.T) {
   277  	h := getTestHandler(t)
   278  	defer h.ctrl.Finish()
   279  
   280  	// given
   281  	name := vgrand.RandomStr(5)
   282  	passphrase := vgrand.RandomStr(5)
   283  
   284  	// when
   285  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   286  
   287  	// then
   288  	require.NoError(t, err)
   289  	assert.NotEmpty(t, recoveryPhrase)
   290  
   291  	// when
   292  	recoveryPhrase, err = h.CreateWallet(name, passphrase)
   293  
   294  	// then
   295  	require.ErrorIs(t, err, wallet.ErrWalletAlreadyExists)
   296  	assert.Empty(t, recoveryPhrase)
   297  }
   298  
   299  func testHandlerRecreatingWalletWithSameNameButDifferentPassphraseFails(t *testing.T) {
   300  	h := getTestHandler(t)
   301  	defer h.ctrl.Finish()
   302  
   303  	// given
   304  	name := vgrand.RandomStr(5)
   305  	passphrase := vgrand.RandomStr(5)
   306  	othPassphrase := "different-passphrase"
   307  
   308  	// when
   309  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   310  
   311  	// then
   312  	require.NoError(t, err)
   313  	assert.NotEmpty(t, recoveryPhrase)
   314  
   315  	// when
   316  	recoveryPhrase, err = h.CreateWallet(name, othPassphrase)
   317  
   318  	// then
   319  	require.ErrorIs(t, err, wallet.ErrWalletAlreadyExists)
   320  	assert.Empty(t, recoveryPhrase)
   321  }
   322  
   323  func testHandlerLoginToExistingWalletSucceeds(t *testing.T) {
   324  	h := getTestHandler(t)
   325  	defer h.ctrl.Finish()
   326  
   327  	// given
   328  	passphrase := vgrand.RandomStr(5)
   329  	name := vgrand.RandomStr(5)
   330  
   331  	// when
   332  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   333  
   334  	// then
   335  	require.NoError(t, err)
   336  	assert.NotEmpty(t, recoveryPhrase)
   337  
   338  	// then
   339  	err = h.LoginWallet(name, passphrase)
   340  
   341  	require.NoError(t, err)
   342  }
   343  
   344  func testHandlerLoginToNonExistingWalletFails(t *testing.T) {
   345  	h := getTestHandler(t)
   346  	defer h.ctrl.Finish()
   347  
   348  	// given
   349  	passphrase := vgrand.RandomStr(5)
   350  	name := vgrand.RandomStr(5)
   351  
   352  	// when
   353  	err := h.LoginWallet(name, passphrase)
   354  
   355  	// then
   356  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   357  }
   358  
   359  func testHandlerGeneratingNewKeyPairSecurelySucceeds(t *testing.T) {
   360  	h := getTestHandler(t)
   361  	defer h.ctrl.Finish()
   362  
   363  	// given
   364  	passphrase := vgrand.RandomStr(5)
   365  	name := vgrand.RandomStr(5)
   366  
   367  	// when
   368  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   369  
   370  	// then
   371  	require.NoError(t, err)
   372  	assert.NotEmpty(t, recoveryPhrase)
   373  
   374  	// when
   375  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   376  
   377  	// then
   378  	require.NoError(t, err)
   379  	assert.NotEmpty(t, key)
   380  
   381  	// when
   382  	keys, err := h.ListPublicKeys(name)
   383  
   384  	// then
   385  	require.NoError(t, err)
   386  	assert.Len(t, keys, 1)
   387  	assert.Equal(t, key, keys[0].Key())
   388  	assert.False(t, keys[0].IsTainted())
   389  	assert.Len(t, keys[0].Metadata(), 1)
   390  	assert.Contains(t, keys[0].Metadata(), wallet.Metadata{Key: "name", Value: "Key 1"})
   391  }
   392  
   393  func testHandlerGeneratingNewKeyPairSecurelyWithInvalidNameFails(t *testing.T) {
   394  	h := getTestHandler(t)
   395  	defer h.ctrl.Finish()
   396  
   397  	// given
   398  	passphrase := vgrand.RandomStr(5)
   399  	name := vgrand.RandomStr(5)
   400  	otherName := vgrand.RandomStr(5)
   401  
   402  	// when
   403  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   404  
   405  	// then
   406  	require.NoError(t, err)
   407  	assert.NotEmpty(t, recoveryPhrase)
   408  
   409  	// when
   410  	key, err := h.SecureGenerateKeyPair(otherName, passphrase, []wallet.Metadata{})
   411  
   412  	// then
   413  	assert.EqualError(t, err, fmt.Sprintf("couldn't unlock wallet %q: wallet does not exist", otherName))
   414  	assert.Empty(t, key)
   415  }
   416  
   417  func testHandlerGeneratingNewKeyPairSecurelyWithoutWalletFails(t *testing.T) {
   418  	h := getTestHandler(t)
   419  	defer h.ctrl.Finish()
   420  
   421  	// given
   422  	name := vgrand.RandomStr(5)
   423  	passphrase := vgrand.RandomStr(5)
   424  
   425  	// when
   426  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   427  
   428  	// then
   429  	assert.EqualError(t, err, fmt.Sprintf("couldn't unlock wallet %q: wallet does not exist", name))
   430  	assert.Empty(t, key)
   431  }
   432  
   433  func testHandlerGeneratingNewKeyPairSucceeds(t *testing.T) {
   434  	h := getTestHandler(t)
   435  	defer h.ctrl.Finish()
   436  
   437  	// given
   438  	passphrase := vgrand.RandomStr(5)
   439  	name := vgrand.RandomStr(5)
   440  
   441  	// when
   442  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   443  
   444  	// then
   445  	require.NoError(t, err)
   446  	assert.NotEmpty(t, recoveryPhrase)
   447  
   448  	// when
   449  	keyPair, err := h.GenerateKeyPair(name, passphrase, nil)
   450  
   451  	// then
   452  	require.NoError(t, err)
   453  	assert.NotEmpty(t, keyPair.PublicKey())
   454  	assert.NotEmpty(t, keyPair.PrivateKey())
   455  	assert.False(t, keyPair.IsTainted())
   456  	assert.Len(t, keyPair.Metadata(), 1)
   457  	assert.Contains(t, keyPair.Metadata(), wallet.Metadata{Key: "name", Value: "Key 1"})
   458  
   459  	// when
   460  	keys, err := h.ListPublicKeys(name)
   461  
   462  	// then
   463  	require.NoError(t, err)
   464  	assert.Len(t, keys, 1)
   465  	assert.Equal(t, keyPair.PublicKey(), keys[0].Key())
   466  	assert.False(t, keys[0].IsTainted())
   467  }
   468  
   469  func testHandlerGeneratingNewKeyPairWithCustomNameSucceeds(t *testing.T) {
   470  	h := getTestHandler(t)
   471  	defer h.ctrl.Finish()
   472  
   473  	// given
   474  	passphrase := vgrand.RandomStr(5)
   475  	name := vgrand.RandomStr(5)
   476  	meta := []wallet.Metadata{
   477  		{
   478  			Key:   "name",
   479  			Value: "crypto-cutie",
   480  		},
   481  	}
   482  
   483  	// when
   484  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   485  
   486  	// then
   487  	require.NoError(t, err)
   488  	assert.NotEmpty(t, recoveryPhrase)
   489  
   490  	// when
   491  	keyPair1, err := h.GenerateKeyPair(name, passphrase, meta)
   492  
   493  	// then
   494  	require.NoError(t, err)
   495  	assert.NotEmpty(t, keyPair1.PublicKey())
   496  	assert.NotEmpty(t, keyPair1.PrivateKey())
   497  	assert.False(t, keyPair1.IsTainted())
   498  	assert.Len(t, keyPair1.Metadata(), 1)
   499  	assert.Contains(t, keyPair1.Metadata(), wallet.Metadata{Key: "name", Value: "crypto-cutie"})
   500  
   501  	// when
   502  	keyPair2, err := h.GenerateKeyPair(name, passphrase, []wallet.Metadata{})
   503  
   504  	// then
   505  	require.NoError(t, err)
   506  	assert.NotEmpty(t, keyPair2.PublicKey())
   507  	assert.NotEmpty(t, keyPair2.PrivateKey())
   508  	assert.False(t, keyPair2.IsTainted())
   509  	assert.Len(t, keyPair2.Metadata(), 1)
   510  	assert.Contains(t, keyPair2.Metadata(), wallet.Metadata{Key: "name", Value: "Key 2"})
   511  
   512  	// when
   513  	keys, err := h.ListPublicKeys(name)
   514  
   515  	// then
   516  	require.NoError(t, err)
   517  	assert.Len(t, keys, 2)
   518  	assert.Equal(t, keyPair1.PublicKey(), keys[0].Key())
   519  	assert.False(t, keys[0].IsTainted())
   520  	assert.Equal(t, keyPair2.PublicKey(), keys[1].Key())
   521  	assert.False(t, keys[1].IsTainted())
   522  }
   523  
   524  func testHandlerGeneratingNewKeyPairWithInvalidNameFails(t *testing.T) {
   525  	h := getTestHandler(t)
   526  	defer h.ctrl.Finish()
   527  
   528  	// given
   529  	passphrase := vgrand.RandomStr(5)
   530  	name := vgrand.RandomStr(5)
   531  	otherName := vgrand.RandomStr(5)
   532  
   533  	// when
   534  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   535  
   536  	// then
   537  	require.NoError(t, err)
   538  	assert.NotEmpty(t, recoveryPhrase)
   539  
   540  	// when
   541  	keyPair, err := h.GenerateKeyPair(otherName, passphrase, nil)
   542  
   543  	// then
   544  	assert.EqualError(t, err, fmt.Sprintf("couldn't unlock wallet %q: wallet does not exist", otherName))
   545  	assert.Empty(t, keyPair)
   546  }
   547  
   548  func testHandlerGeneratingNewKeyPairWithoutWalletFails(t *testing.T) {
   549  	h := getTestHandler(t)
   550  	defer h.ctrl.Finish()
   551  
   552  	// given
   553  	name := vgrand.RandomStr(5)
   554  	passphrase := vgrand.RandomStr(5)
   555  
   556  	// when
   557  	keyPair, err := h.GenerateKeyPair(name, passphrase, nil)
   558  
   559  	// then
   560  	assert.EqualError(t, err, fmt.Sprintf("couldn't unlock wallet %q: wallet does not exist", name))
   561  	assert.Empty(t, keyPair)
   562  }
   563  
   564  func testHandlerListingPublicKeysSucceeds(t *testing.T) {
   565  	h := getTestHandler(t)
   566  	defer h.ctrl.Finish()
   567  
   568  	// given
   569  	passphrase := vgrand.RandomStr(5)
   570  	name := vgrand.RandomStr(5)
   571  
   572  	// when
   573  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   574  
   575  	// then
   576  	require.NoError(t, err)
   577  	assert.NotEmpty(t, recoveryPhrase)
   578  
   579  	// when
   580  	keyPair, err := h.GenerateKeyPair(name, passphrase, nil)
   581  
   582  	// then
   583  	require.NoError(t, err)
   584  	assert.NotNil(t, keyPair)
   585  
   586  	// when
   587  	publicKeys, err := h.ListPublicKeys(name)
   588  
   589  	// then
   590  	require.NoError(t, err)
   591  	assert.Len(t, publicKeys, 1)
   592  	returnedPublicKey := publicKeys[0]
   593  	assert.Equal(t, keyPair.PublicKey(), returnedPublicKey.Key())
   594  	assert.Equal(t, keyPair.IsTainted(), returnedPublicKey.IsTainted())
   595  	assert.Equal(t, keyPair.AlgorithmName(), returnedPublicKey.AlgorithmName())
   596  	assert.Equal(t, keyPair.AlgorithmVersion(), returnedPublicKey.AlgorithmVersion())
   597  	assert.Equal(t, keyPair.Metadata(), returnedPublicKey.Metadata())
   598  }
   599  
   600  func testHandlerListingPublicKeysWithInvalidNameFails(t *testing.T) {
   601  	h := getTestHandler(t)
   602  	defer h.ctrl.Finish()
   603  
   604  	// given
   605  	passphrase := vgrand.RandomStr(5)
   606  	name := vgrand.RandomStr(5)
   607  	otherName := vgrand.RandomStr(5)
   608  
   609  	// when
   610  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   611  
   612  	// then
   613  	require.NoError(t, err)
   614  	assert.NotEmpty(t, recoveryPhrase)
   615  
   616  	// when
   617  	key, err := h.ListPublicKeys(otherName)
   618  
   619  	// then
   620  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   621  	assert.Empty(t, key)
   622  }
   623  
   624  func testHandlerListingPublicKeysWithoutWalletFails(t *testing.T) {
   625  	h := getTestHandler(t)
   626  	defer h.ctrl.Finish()
   627  
   628  	// given
   629  	name := vgrand.RandomStr(5)
   630  
   631  	// when
   632  	key, err := h.ListPublicKeys(name)
   633  
   634  	// then
   635  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   636  	assert.Empty(t, key)
   637  }
   638  
   639  func testHandlerListingKeyPairsSucceeds(t *testing.T) {
   640  	h := getTestHandler(t)
   641  	defer h.ctrl.Finish()
   642  
   643  	// given
   644  	passphrase := vgrand.RandomStr(5)
   645  	name := vgrand.RandomStr(5)
   646  
   647  	// when
   648  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   649  
   650  	// then
   651  	require.NoError(t, err)
   652  	assert.NotEmpty(t, recoveryPhrase)
   653  
   654  	// when
   655  	keyPair, err := h.GenerateKeyPair(name, passphrase, nil)
   656  
   657  	// then
   658  	require.NoError(t, err)
   659  	assert.NotNil(t, keyPair)
   660  
   661  	// when
   662  	publicKeys, err := h.ListKeyPairs(name)
   663  
   664  	// then
   665  	require.NoError(t, err)
   666  	assert.Len(t, publicKeys, 1)
   667  	returnedPublicKey := publicKeys[0]
   668  	assert.Equal(t, keyPair.PublicKey(), returnedPublicKey.PublicKey())
   669  	assert.Equal(t, keyPair.PrivateKey(), returnedPublicKey.PrivateKey())
   670  	assert.Equal(t, keyPair.IsTainted(), returnedPublicKey.IsTainted())
   671  	assert.Equal(t, keyPair.AlgorithmName(), returnedPublicKey.AlgorithmName())
   672  	assert.Equal(t, keyPair.AlgorithmVersion(), returnedPublicKey.AlgorithmVersion())
   673  	assert.Equal(t, keyPair.Metadata(), returnedPublicKey.Metadata())
   674  }
   675  
   676  func testHandlerListingKeyPairsWithInvalidNameFails(t *testing.T) {
   677  	h := getTestHandler(t)
   678  	defer h.ctrl.Finish()
   679  
   680  	// given
   681  	passphrase := vgrand.RandomStr(5)
   682  	name := vgrand.RandomStr(5)
   683  	otherName := vgrand.RandomStr(5)
   684  
   685  	// when
   686  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   687  
   688  	// then
   689  	require.NoError(t, err)
   690  	assert.NotEmpty(t, recoveryPhrase)
   691  
   692  	// when
   693  	key, err := h.ListKeyPairs(otherName)
   694  
   695  	// then
   696  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   697  	assert.Empty(t, key)
   698  }
   699  
   700  func testHandlerListingKeyPairsWithoutWalletFails(t *testing.T) {
   701  	h := getTestHandler(t)
   702  	defer h.ctrl.Finish()
   703  
   704  	// given
   705  	name := vgrand.RandomStr(5)
   706  
   707  	// when
   708  	key, err := h.ListKeyPairs(name)
   709  
   710  	// then
   711  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   712  	assert.Empty(t, key)
   713  }
   714  
   715  func testHandlerGettingPublicKeyWithoutWalletFails(t *testing.T) {
   716  	h := getTestHandler(t)
   717  	defer h.ctrl.Finish()
   718  
   719  	// given
   720  	name := vgrand.RandomStr(5)
   721  
   722  	// when
   723  	key, err := h.GetPublicKey(name, name)
   724  
   725  	// then
   726  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   727  	assert.Empty(t, key)
   728  }
   729  
   730  func testHandlerGettingPublicKeySucceeds(t *testing.T) {
   731  	h := getTestHandler(t)
   732  	defer h.ctrl.Finish()
   733  
   734  	// given
   735  	passphrase := vgrand.RandomStr(5)
   736  	name := vgrand.RandomStr(5)
   737  
   738  	// when
   739  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   740  
   741  	// then
   742  	require.NoError(t, err)
   743  	assert.NotEmpty(t, recoveryPhrase)
   744  
   745  	// when
   746  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   747  
   748  	// then
   749  	require.NoError(t, err)
   750  	assert.NotEmpty(t, key)
   751  
   752  	// when
   753  	keyPair, err := h.GetPublicKey(name, key)
   754  
   755  	require.NoError(t, err)
   756  	assert.Equal(t, key, keyPair.Key())
   757  }
   758  
   759  func testHandlerGettingPublicKeyWithInvalidNameFails(t *testing.T) {
   760  	h := getTestHandler(t)
   761  	defer h.ctrl.Finish()
   762  
   763  	// given
   764  	passphrase := vgrand.RandomStr(5)
   765  	name := vgrand.RandomStr(5)
   766  	otherName := vgrand.RandomStr(5)
   767  
   768  	// when
   769  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   770  
   771  	// then
   772  	require.NoError(t, err)
   773  	assert.NotEmpty(t, recoveryPhrase)
   774  
   775  	// when
   776  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   777  
   778  	// then
   779  	require.NoError(t, err)
   780  	assert.NotEmpty(t, key)
   781  
   782  	// when
   783  	keyPair, err := h.GetPublicKey(otherName, key)
   784  
   785  	// then
   786  	assert.ErrorIs(t, err, wallets.ErrWalletDoesNotExists)
   787  	assert.Nil(t, keyPair)
   788  }
   789  
   790  func testGettingNonExistingPublicKeyFails(t *testing.T) {
   791  	h := getTestHandler(t)
   792  	defer h.ctrl.Finish()
   793  
   794  	// given
   795  	passphrase := vgrand.RandomStr(5)
   796  	name := vgrand.RandomStr(5)
   797  
   798  	// when
   799  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   800  
   801  	// then
   802  	require.NoError(t, err)
   803  	assert.NotEmpty(t, recoveryPhrase)
   804  
   805  	// when
   806  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   807  
   808  	// then
   809  	require.NoError(t, err)
   810  	assert.NotEmpty(t, key)
   811  
   812  	// when
   813  	keyPair, err := h.GetPublicKey(name, "non-existing-pub-key")
   814  	assert.ErrorIs(t, err, wallet.ErrPubKeyDoesNotExist)
   815  	assert.Nil(t, keyPair)
   816  }
   817  
   818  func testHandlerTaintingKeyPairSucceeds(t *testing.T) {
   819  	h := getTestHandler(t)
   820  	defer h.ctrl.Finish()
   821  
   822  	// given
   823  	passphrase := vgrand.RandomStr(5)
   824  	name := vgrand.RandomStr(5)
   825  
   826  	// when
   827  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   828  
   829  	// then
   830  	require.NoError(t, err)
   831  	assert.NotEmpty(t, recoveryPhrase)
   832  
   833  	// when
   834  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   835  
   836  	// then
   837  	require.NoError(t, err)
   838  	assert.NotEmpty(t, key)
   839  
   840  	// when
   841  	publicKey, err := h.GetPublicKey(name, key)
   842  
   843  	// then
   844  	require.NoError(t, err)
   845  	assert.NotNil(t, publicKey)
   846  	assert.False(t, publicKey.IsTainted())
   847  
   848  	// when
   849  	err = h.TaintKey(name, key, passphrase)
   850  
   851  	// then
   852  	require.NoError(t, err)
   853  	assert.True(t, h.store.GetKey(name, key).IsTainted())
   854  }
   855  
   856  func testHandlerTaintingKeyPairWithInvalidNameFails(t *testing.T) {
   857  	h := getTestHandler(t)
   858  	defer h.ctrl.Finish()
   859  
   860  	// given
   861  	passphrase := vgrand.RandomStr(5)
   862  	name := vgrand.RandomStr(5)
   863  
   864  	otherName := "other name"
   865  
   866  	// when
   867  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   868  
   869  	// then
   870  	require.NoError(t, err)
   871  	assert.NotEmpty(t, recoveryPhrase)
   872  
   873  	// when
   874  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   875  
   876  	// then
   877  	require.NoError(t, err)
   878  	assert.NotEmpty(t, key)
   879  
   880  	// when
   881  	keyPair, err := h.GetPublicKey(name, key)
   882  
   883  	// then
   884  	require.NoError(t, err)
   885  	assert.NotNil(t, keyPair)
   886  	assert.False(t, keyPair.IsTainted())
   887  
   888  	// when
   889  	err = h.TaintKey(otherName, key, passphrase)
   890  
   891  	// then
   892  	assert.Error(t, err)
   893  }
   894  
   895  func testHandlerTaintingKeyPairWithoutWalletFails(t *testing.T) {
   896  	h := getTestHandler(t)
   897  	defer h.ctrl.Finish()
   898  
   899  	// given
   900  	passphrase := vgrand.RandomStr(5)
   901  	name := vgrand.RandomStr(5)
   902  
   903  	// when
   904  	err := h.TaintKey(name, "non-existing-pub-key", passphrase)
   905  
   906  	// then
   907  	assert.EqualError(t, err, fmt.Sprintf("couldn't unlock wallet %q: wallet does not exist", name))
   908  }
   909  
   910  func testHandlerTaintingKeyThatIsAlreadyTaintedFails(t *testing.T) {
   911  	h := getTestHandler(t)
   912  	defer h.ctrl.Finish()
   913  
   914  	// given
   915  	passphrase := vgrand.RandomStr(5)
   916  	name := vgrand.RandomStr(5)
   917  
   918  	// when
   919  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   920  
   921  	// then
   922  	require.NoError(t, err)
   923  	assert.NotEmpty(t, recoveryPhrase)
   924  
   925  	// when
   926  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   927  
   928  	// then
   929  	require.NoError(t, err)
   930  	assert.NotEmpty(t, key)
   931  
   932  	// when
   933  	keyPair, err := h.GetPublicKey(name, key)
   934  
   935  	// then
   936  	require.NoError(t, err)
   937  	assert.NotNil(t, keyPair)
   938  	assert.False(t, keyPair.IsTainted())
   939  
   940  	// when
   941  	err = h.TaintKey(name, key, passphrase)
   942  
   943  	// then
   944  	require.NoError(t, err)
   945  	assert.True(t, h.store.GetKey(name, key).IsTainted())
   946  
   947  	// when
   948  	err = h.TaintKey(name, key, passphrase)
   949  
   950  	// then
   951  	assert.ErrorIs(t, err, wallet.ErrPubKeyAlreadyTainted)
   952  }
   953  
   954  func testHandlerUpdatingKeyPairMetaSucceeds(t *testing.T) {
   955  	h := getTestHandler(t)
   956  	defer h.ctrl.Finish()
   957  
   958  	// given
   959  	passphrase := vgrand.RandomStr(5)
   960  	name := vgrand.RandomStr(5)
   961  
   962  	meta := []wallet.Metadata{{Key: "primary", Value: "yes"}}
   963  
   964  	// when
   965  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
   966  
   967  	// then
   968  	require.NoError(t, err)
   969  	assert.NotEmpty(t, recoveryPhrase)
   970  
   971  	// when
   972  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
   973  
   974  	// then
   975  	require.NoError(t, err)
   976  	assert.NotEmpty(t, key)
   977  
   978  	// when
   979  	err = h.UpdateMeta(name, key, passphrase, meta)
   980  
   981  	// then
   982  	require.NoError(t, err)
   983  	updatedKp := h.store.GetKey(name, key)
   984  	assert.Len(t, updatedKp.Metadata(), 2)
   985  	assert.Equal(t, updatedKp.Metadata()[0].Key, "primary")
   986  	assert.Equal(t, updatedKp.Metadata()[0].Value, "yes")
   987  	assert.Equal(t, updatedKp.Metadata()[1].Key, "name")
   988  	assert.Equal(t, updatedKp.Metadata()[1].Value, "Key 1")
   989  }
   990  
   991  func testHandlerUpdatingKeyPairMetaWithInvalidPassphraseFails(t *testing.T) {
   992  	h := getTestHandler(t)
   993  	defer h.ctrl.Finish()
   994  
   995  	// given
   996  	passphrase := vgrand.RandomStr(5)
   997  	othPassphrase := "other-passphrase"
   998  	name := vgrand.RandomStr(5)
   999  
  1000  	meta := []wallet.Metadata{{Key: "primary", Value: "yes"}}
  1001  
  1002  	// when
  1003  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1004  
  1005  	// then
  1006  	require.NoError(t, err)
  1007  	assert.NotEmpty(t, recoveryPhrase)
  1008  
  1009  	// when
  1010  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1011  
  1012  	// then
  1013  	require.NoError(t, err)
  1014  	assert.NotEmpty(t, key)
  1015  
  1016  	// when
  1017  	err = h.UpdateMeta(name, key, othPassphrase, meta)
  1018  
  1019  	// then
  1020  	assert.Error(t, err)
  1021  	assert.NotContains(t, h.store.GetKey(name, key).Metadata(), wallet.Metadata{Key: "primary", Value: "yes"})
  1022  }
  1023  
  1024  func testHandlerUpdatingKeyPairMetaWithInvalidNameFails(t *testing.T) {
  1025  	h := getTestHandler(t)
  1026  	defer h.ctrl.Finish()
  1027  
  1028  	// given
  1029  	passphrase := vgrand.RandomStr(5)
  1030  	name := vgrand.RandomStr(5)
  1031  	otherName := "other name"
  1032  	meta := []wallet.Metadata{{Key: "primary", Value: "yes"}}
  1033  
  1034  	// when
  1035  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1036  
  1037  	// then
  1038  	require.NoError(t, err)
  1039  	assert.NotEmpty(t, recoveryPhrase)
  1040  
  1041  	// when
  1042  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1043  
  1044  	// then
  1045  	require.NoError(t, err)
  1046  	assert.NotEmpty(t, key)
  1047  
  1048  	// when
  1049  	err = h.UpdateMeta(otherName, key, passphrase, meta)
  1050  
  1051  	// then
  1052  	assert.Error(t, err)
  1053  	assert.NotContains(t, h.store.GetKey(name, key).Metadata(), wallet.Metadata{Key: "primary", Value: "yes"})
  1054  }
  1055  
  1056  func testHandlerUpdatingKeyPairMetaWithoutWalletFails(t *testing.T) {
  1057  	h := getTestHandler(t)
  1058  	defer h.ctrl.Finish()
  1059  
  1060  	// given
  1061  	passphrase := vgrand.RandomStr(5)
  1062  	name := vgrand.RandomStr(5)
  1063  	pubKey := "non-existing-public-key"
  1064  	meta := []wallet.Metadata{{Key: "primary", Value: "yes"}}
  1065  
  1066  	// when
  1067  	err := h.UpdateMeta(name, pubKey, passphrase, meta)
  1068  
  1069  	// then
  1070  	assert.Error(t, err)
  1071  }
  1072  
  1073  func testHandlerUpdatingKeyPairMetaWithNonExistingPublicKeyFails(t *testing.T) {
  1074  	h := getTestHandler(t)
  1075  	defer h.ctrl.Finish()
  1076  
  1077  	// given
  1078  	passphrase := vgrand.RandomStr(5)
  1079  	name := vgrand.RandomStr(5)
  1080  	pubKey := "non-existing-public-key"
  1081  	meta := []wallet.Metadata{{Key: "primary", Value: "yes"}}
  1082  
  1083  	// when
  1084  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1085  
  1086  	// then
  1087  	require.NoError(t, err)
  1088  	assert.NotEmpty(t, recoveryPhrase)
  1089  
  1090  	// when
  1091  	key, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1092  
  1093  	// then
  1094  	require.NoError(t, err)
  1095  	assert.NotEmpty(t, key)
  1096  
  1097  	// when
  1098  	err = h.UpdateMeta(name, pubKey, passphrase, meta)
  1099  
  1100  	// then
  1101  	assert.Error(t, err)
  1102  }
  1103  
  1104  func testHandlerGettingWalletPathSucceeds(t *testing.T) {
  1105  	h := getTestHandler(t)
  1106  	defer h.ctrl.Finish()
  1107  
  1108  	// given
  1109  	name := vgrand.RandomStr(5)
  1110  
  1111  	// when
  1112  	path, err := h.GetWalletPath(name)
  1113  
  1114  	// then
  1115  	require.NoError(t, err)
  1116  	assert.NotEmpty(t, path)
  1117  }
  1118  
  1119  func testHandlerSigningTxSucceeds(t *testing.T) {
  1120  	h := getTestHandler(t)
  1121  	defer h.ctrl.Finish()
  1122  
  1123  	// given
  1124  	passphrase := vgrand.RandomStr(5)
  1125  	name := vgrand.RandomStr(5)
  1126  
  1127  	// when
  1128  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1129  
  1130  	// then
  1131  	require.NoError(t, err)
  1132  	assert.NotEmpty(t, recoveryPhrase)
  1133  
  1134  	// when
  1135  	pubKey, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1136  
  1137  	// then
  1138  	require.NoError(t, err)
  1139  	assert.NotEmpty(t, pubKey)
  1140  
  1141  	// given
  1142  	req := &walletpb.SubmitTransactionRequest{
  1143  		PubKey: pubKey,
  1144  		Command: &walletpb.SubmitTransactionRequest_OrderCancellation{
  1145  			OrderCancellation: &commandspb.OrderCancellation{},
  1146  		},
  1147  	}
  1148  
  1149  	// when
  1150  	tx, err := h.SignTx(name, req, 42, vgrand.RandomStr(5))
  1151  
  1152  	// then
  1153  	require.NoError(t, err)
  1154  	assert.Equal(t, commandspb.TxVersion(3), tx.Version)
  1155  	assert.NotEmpty(t, tx.From)
  1156  	assert.Equal(t, tx.GetPubKey(), pubKey)
  1157  	assert.NotEmpty(t, tx.InputData)
  1158  	assert.NotNil(t, tx.Signature)
  1159  	key := h.store.GetKey(name, pubKey)
  1160  	assert.Equal(t, key.AlgorithmVersion(), tx.Signature.Version)
  1161  	assert.Equal(t, key.AlgorithmName(), tx.Signature.Algo)
  1162  	assert.NotEmpty(t, tx.Signature.Value)
  1163  }
  1164  
  1165  func testHandlerSigningTxWithTaintedKeyFails(t *testing.T) {
  1166  	h := getTestHandler(t)
  1167  	defer h.ctrl.Finish()
  1168  
  1169  	// given
  1170  	passphrase := vgrand.RandomStr(5)
  1171  	name := vgrand.RandomStr(5)
  1172  
  1173  	// when
  1174  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1175  
  1176  	// then
  1177  	require.NoError(t, err)
  1178  	assert.NotEmpty(t, recoveryPhrase)
  1179  
  1180  	// when
  1181  	pubKey, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1182  
  1183  	// then
  1184  	require.NoError(t, err)
  1185  	assert.NotEmpty(t, pubKey)
  1186  
  1187  	// when
  1188  	err = h.TaintKey(name, pubKey, passphrase)
  1189  
  1190  	// then
  1191  	require.NoError(t, err)
  1192  	assert.True(t, h.store.GetKey(name, pubKey).IsTainted())
  1193  
  1194  	// given
  1195  	req := &walletpb.SubmitTransactionRequest{
  1196  		PubKey: pubKey,
  1197  		Command: &walletpb.SubmitTransactionRequest_OrderCancellation{
  1198  			OrderCancellation: &commandspb.OrderCancellation{},
  1199  		},
  1200  	}
  1201  
  1202  	// when
  1203  	tx, err := h.SignTx(name, req, 42, vgrand.RandomStr(5))
  1204  
  1205  	// then
  1206  	assert.Error(t, err)
  1207  	assert.Nil(t, tx)
  1208  }
  1209  
  1210  func testHandlerSigningAndVerifyingMessageSucceeds(t *testing.T) {
  1211  	h := getTestHandler(t)
  1212  	defer h.ctrl.Finish()
  1213  
  1214  	// given
  1215  	passphrase := vgrand.RandomStr(5)
  1216  	name := vgrand.RandomStr(5)
  1217  
  1218  	// when
  1219  	recoveryPhrase, err := h.CreateWallet(name, passphrase)
  1220  
  1221  	// then
  1222  	require.NoError(t, err)
  1223  	assert.NotEmpty(t, recoveryPhrase)
  1224  
  1225  	// when
  1226  	pubKey, err := h.SecureGenerateKeyPair(name, passphrase, []wallet.Metadata{})
  1227  
  1228  	// then
  1229  	require.NoError(t, err)
  1230  	assert.NotEmpty(t, pubKey)
  1231  
  1232  	// given
  1233  	data := []byte("Je ne connaîtrai pas la peur car la peur tue l'esprit. La peur est la petite mort qui conduit à l'oblitération totale.")
  1234  
  1235  	// when
  1236  	sig, err := h.SignAny(name, data, pubKey)
  1237  
  1238  	// then
  1239  	require.NoError(t, err)
  1240  	assert.NotEmpty(t, sig)
  1241  
  1242  	// when
  1243  	verified, err := h.VerifyAny(data, sig, pubKey)
  1244  
  1245  	// then
  1246  	require.NoError(t, err)
  1247  	assert.True(t, verified)
  1248  }