github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/accounts/pluggable/wallet_test.go (about) 1 package pluggable 2 3 import ( 4 "math/big" 5 "math/rand" 6 "testing" 7 8 "github.com/ethereum/go-ethereum/accounts" 9 "github.com/ethereum/go-ethereum/accounts/pluggable/internal/testutils/mock_plugin" 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/ethereum/go-ethereum/core/types" 12 "github.com/ethereum/go-ethereum/crypto" 13 "github.com/golang/mock/gomock" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 var ( 19 scheme = "scheme" 20 21 wltUrl = accounts.URL{ 22 Scheme: scheme, 23 Path: "uripath", 24 } 25 26 acct1 = accounts.Account{ 27 Address: common.HexToAddress("0x4d6d744b6da435b5bbdde2526dc20e9a41cb72e5"), 28 URL: wltUrl, 29 } 30 31 acct2 = accounts.Account{ 32 Address: common.HexToAddress("0x2332f90a329c2c55ba120b1449d36a144d1f9fe4"), 33 URL: accounts.URL{Scheme: scheme, Path: "path/to/file2.json"}, 34 } 35 acct3 = accounts.Account{ 36 Address: common.HexToAddress("0x992d7a8fca612c963796ecbfe78b300370b9545a"), 37 URL: accounts.URL{Scheme: scheme, Path: "path/to/file3.json"}, 38 } 39 acct4 = accounts.Account{ 40 Address: common.HexToAddress("0x39ac8f3ae3681b4422fdf808ae18ba4365e37da8"), 41 URL: accounts.URL{Scheme: scheme, Path: "path/to/file4.json"}, 42 } 43 ) 44 45 func validWallet(m *mock_plugin.MockService) *wallet { 46 return &wallet{ 47 url: wltUrl, 48 pluginService: m, 49 } 50 } 51 52 func TestWallet_Url(t *testing.T) { 53 w := validWallet(nil) 54 got := w.URL() 55 assert.Equal(t, wltUrl, got) 56 } 57 58 func TestWallet_Status(t *testing.T) { 59 ctrl := gomock.NewController(t) 60 defer ctrl.Finish() 61 62 want := "status" 63 64 mockClient := mock_plugin.NewMockService(ctrl) 65 mockClient. 66 EXPECT(). 67 Status(gomock.Any()). 68 Return(want, nil) 69 70 w := validWallet(mockClient) 71 status, err := w.Status() 72 73 assert.NoError(t, err) 74 assert.Equal(t, want, status) 75 } 76 77 func TestWallet_Open(t *testing.T) { 78 ctrl := gomock.NewController(t) 79 defer ctrl.Finish() 80 81 mockClient := mock_plugin.NewMockService(ctrl) 82 mockClient. 83 EXPECT(). 84 Open(gomock.Any(), "pwd"). 85 Return(nil) 86 87 w := validWallet(mockClient) 88 err := w.Open("pwd") 89 90 assert.NoError(t, err) 91 } 92 93 func TestWallet_Close(t *testing.T) { 94 ctrl := gomock.NewController(t) 95 defer ctrl.Finish() 96 97 mockClient := mock_plugin.NewMockService(ctrl) 98 mockClient. 99 EXPECT(). 100 Close(gomock.Any()). 101 Return(nil) 102 103 w := validWallet(mockClient) 104 err := w.Close() 105 106 assert.NoError(t, err) 107 } 108 109 func TestWallet_Accounts(t *testing.T) { 110 ctrl := gomock.NewController(t) 111 defer ctrl.Finish() 112 113 want := []accounts.Account{acct1, acct2, acct3, acct4} 114 115 mockClient := mock_plugin.NewMockService(ctrl) 116 mockClient. 117 EXPECT(). 118 Accounts(gomock.Any()). 119 Return(want) 120 121 w := validWallet(mockClient) 122 got := w.Accounts() 123 124 assert.Equal(t, want, got) 125 } 126 127 func TestWallet_Contains(t *testing.T) { 128 ctrl := gomock.NewController(t) 129 defer ctrl.Finish() 130 131 mockClient := mock_plugin.NewMockService(ctrl) 132 mockClient. 133 EXPECT(). 134 Contains(gomock.Any(), acct1). 135 Return(true) 136 137 w := validWallet(mockClient) 138 got := w.Contains(acct1) 139 140 assert.True(t, got) 141 } 142 143 func TestWallet_Derive(t *testing.T) { 144 w := validWallet(nil) 145 _, err := w.Derive(accounts.DerivationPath{}, true) 146 if assert.Error(t, err) { 147 assert.Equal(t, accounts.ErrNotSupported, err) 148 } 149 } 150 151 func TestWallet_SelfDerive(t *testing.T) { 152 w := validWallet(nil) 153 // does nothing 154 w.SelfDerive([]accounts.DerivationPath{}, nil) 155 } 156 157 func TestWallet_SignData(t *testing.T) { 158 ctrl := gomock.NewController(t) 159 defer ctrl.Finish() 160 161 toSign := []byte("somedata") 162 want := []byte("signeddata") 163 164 mockClient := mock_plugin.NewMockService(ctrl) 165 mockClient. 166 EXPECT(). 167 Sign(gomock.Any(), acct1, crypto.Keccak256(toSign)). 168 Return(want, nil) 169 170 w := validWallet(mockClient) 171 got, err := w.SignData(acct1, "", toSign) 172 173 assert.NoError(t, err) 174 assert.Equal(t, want, got) 175 } 176 177 func TestWallet_SignDataWithPassphrase(t *testing.T) { 178 ctrl := gomock.NewController(t) 179 defer ctrl.Finish() 180 181 toSign := []byte("somedata") 182 want := []byte("signeddata") 183 184 mockClient := mock_plugin.NewMockService(ctrl) 185 mockClient. 186 EXPECT(). 187 UnlockAndSign(gomock.Any(), acct1, crypto.Keccak256(toSign), "pwd"). 188 Return(want, nil) 189 190 w := validWallet(mockClient) 191 got, err := w.SignDataWithPassphrase(acct1, "pwd", "", toSign) 192 193 assert.NoError(t, err) 194 assert.Equal(t, want, got) 195 } 196 197 func TestWallet_SignText(t *testing.T) { 198 ctrl := gomock.NewController(t) 199 defer ctrl.Finish() 200 201 toSign := []byte("somedata") 202 want := []byte("signeddata") 203 204 mockClient := mock_plugin.NewMockService(ctrl) 205 mockClient. 206 EXPECT(). 207 Sign(gomock.Any(), acct1, accounts.TextHash(toSign)). 208 Return(want, nil) 209 210 w := validWallet(mockClient) 211 got, err := w.SignText(acct1, toSign) 212 213 assert.NoError(t, err) 214 assert.Equal(t, want, got) 215 } 216 217 func TestWallet_SignTextWithPassphrase(t *testing.T) { 218 ctrl := gomock.NewController(t) 219 defer ctrl.Finish() 220 221 toSign := []byte("somedata") 222 want := []byte("signeddata") 223 224 mockClient := mock_plugin.NewMockService(ctrl) 225 mockClient. 226 EXPECT(). 227 UnlockAndSign(gomock.Any(), acct1, accounts.TextHash(toSign), "pwd"). 228 Return(want, nil) 229 230 w := validWallet(mockClient) 231 got, err := w.SignTextWithPassphrase(acct1, "pwd", toSign) 232 233 assert.NoError(t, err) 234 assert.Equal(t, want, got) 235 } 236 237 func TestWallet_SignTx(t *testing.T) { 238 ctrl := gomock.NewController(t) 239 defer ctrl.Finish() 240 241 tests := []struct { 242 name string 243 isPrivate bool 244 chainID *big.Int 245 signer types.Signer 246 }{ 247 { 248 name: "Public EIP155 tx", 249 isPrivate: false, 250 chainID: big.NewInt(20), 251 signer: types.NewEIP155Signer(big.NewInt(20)), 252 }, 253 { 254 name: "Public Homestead tx", 255 isPrivate: false, 256 chainID: nil, 257 signer: types.HomesteadSigner{}, 258 }, 259 { 260 name: "Private tx", 261 isPrivate: true, 262 chainID: nil, 263 signer: types.QuorumPrivateTxSigner{}, 264 }, 265 } 266 267 toSign := types.NewTransaction( 268 1, 269 common.HexToAddress("0x2332f90a329c2c55ba120b1449d36a144d1f9fe4"), 270 big.NewInt(1), 271 0, 272 big.NewInt(1), 273 nil, 274 ) 275 276 for _, tt := range tests { 277 t.Run(tt.name, func(t *testing.T) { 278 if tt.isPrivate { 279 toSign.SetPrivate() 280 } 281 282 hashToSign := tt.signer.Hash(toSign) 283 284 mockSig := make([]byte, 65) 285 rand.Read(mockSig) 286 287 mockClient := mock_plugin.NewMockService(ctrl) 288 mockClient. 289 EXPECT(). 290 Sign(gomock.Any(), acct1, hashToSign.Bytes()). 291 Return(mockSig, nil) 292 293 w := validWallet(mockClient) 294 got, err := w.SignTx(acct1, toSign, tt.chainID) 295 require.NoError(t, err) 296 297 gotV, gotR, gotS := got.RawSignatureValues() 298 299 wantR, wantS, wantV, err := tt.signer.SignatureValues(types.NewTransaction( 300 0, 301 common.Address{}, 302 nil, 303 0, 304 nil, 305 nil, 306 ), mockSig) // tx param is unused by method 307 require.NoError(t, err) 308 309 // assert the correct signature is added to the tx 310 assert.Equal(t, wantV, gotV) 311 assert.Equal(t, wantR, gotR) 312 assert.Equal(t, wantS, gotS) 313 314 // assert the rest of the tx is unchanged 315 assert.Equal(t, toSign.Nonce(), got.Nonce()) 316 assert.Equal(t, toSign.GasPrice(), got.GasPrice()) 317 assert.Equal(t, toSign.Gas(), got.Gas()) 318 assert.Equal(t, toSign.To(), got.To()) 319 assert.Equal(t, toSign.Value(), got.Value()) 320 assert.Equal(t, toSign.Data(), got.Data()) 321 }) 322 } 323 } 324 325 func TestWallet_SignTxWithPassphrase(t *testing.T) { 326 ctrl := gomock.NewController(t) 327 defer ctrl.Finish() 328 329 tests := []struct { 330 name string 331 isPrivate bool 332 chainID *big.Int 333 signer types.Signer 334 }{ 335 { 336 name: "Public EIP155 tx", 337 isPrivate: false, 338 chainID: big.NewInt(20), 339 signer: types.NewEIP155Signer(big.NewInt(20)), 340 }, 341 { 342 name: "Public Homestead tx", 343 isPrivate: false, 344 chainID: nil, 345 signer: types.HomesteadSigner{}, 346 }, 347 { 348 name: "Private tx", 349 isPrivate: true, 350 chainID: nil, 351 signer: types.QuorumPrivateTxSigner{}, 352 }, 353 } 354 355 toSign := types.NewTransaction( 356 1, 357 common.HexToAddress("0x2332f90a329c2c55ba120b1449d36a144d1f9fe4"), 358 big.NewInt(1), 359 0, 360 big.NewInt(1), 361 nil, 362 ) 363 364 for _, tt := range tests { 365 t.Run(tt.name, func(t *testing.T) { 366 if tt.isPrivate { 367 toSign.SetPrivate() 368 } 369 370 hashToSign := tt.signer.Hash(toSign) 371 372 mockSig := make([]byte, 65) 373 rand.Read(mockSig) 374 375 mockClient := mock_plugin.NewMockService(ctrl) 376 mockClient. 377 EXPECT(). 378 UnlockAndSign(gomock.Any(), acct1, hashToSign.Bytes(), "pwd"). 379 Return(mockSig, nil) 380 381 w := validWallet(mockClient) 382 got, err := w.SignTxWithPassphrase(acct1, "pwd", toSign, tt.chainID) 383 require.NoError(t, err) 384 385 gotV, gotR, gotS := got.RawSignatureValues() 386 387 wantR, wantS, wantV, err := tt.signer.SignatureValues(types.NewTransaction( 388 0, 389 common.Address{}, 390 nil, 391 0, 392 nil, 393 nil, 394 ), mockSig) // tx param is unused by method 395 require.NoError(t, err) 396 397 // assert the correct signature is added to the tx 398 assert.Equal(t, wantV, gotV) 399 assert.Equal(t, wantR, gotR) 400 assert.Equal(t, wantS, gotS) 401 402 // assert the rest of the tx is unchanged 403 assert.Equal(t, toSign.Nonce(), got.Nonce()) 404 assert.Equal(t, toSign.GasPrice(), got.GasPrice()) 405 assert.Equal(t, toSign.Gas(), got.Gas()) 406 assert.Equal(t, toSign.To(), got.To()) 407 assert.Equal(t, toSign.Value(), got.Value()) 408 assert.Equal(t, toSign.Data(), got.Data()) 409 }) 410 } 411 }