github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/accounts/pluggable/wallet_test.go (about) 1 package pluggable 2 3 import ( 4 "math/big" 5 "math/rand" 6 "testing" 7 8 "github.com/kisexp/xdchain/accounts" 9 "github.com/kisexp/xdchain/accounts/pluggable/internal/testutils/mock_plugin" 10 "github.com/kisexp/xdchain/common" 11 "github.com/kisexp/xdchain/core/types" 12 "github.com/kisexp/xdchain/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.Transaction{}, mockSig) // tx param is unused by method 300 require.NoError(t, err) 301 302 // assert the correct signature is added to the tx 303 assert.Equal(t, wantV, gotV) 304 assert.Equal(t, wantR, gotR) 305 assert.Equal(t, wantS, gotS) 306 307 // assert the rest of the tx is unchanged 308 assert.Equal(t, toSign.Nonce(), got.Nonce()) 309 assert.Equal(t, toSign.GasPrice(), got.GasPrice()) 310 assert.Equal(t, toSign.Gas(), got.Gas()) 311 assert.Equal(t, toSign.To(), got.To()) 312 assert.Equal(t, toSign.Value(), got.Value()) 313 assert.Equal(t, toSign.Data(), got.Data()) 314 }) 315 } 316 } 317 318 func TestWallet_SignTxWithPassphrase(t *testing.T) { 319 ctrl := gomock.NewController(t) 320 defer ctrl.Finish() 321 322 tests := []struct { 323 name string 324 isPrivate bool 325 chainID *big.Int 326 signer types.Signer 327 }{ 328 { 329 name: "Public EIP155 tx", 330 isPrivate: false, 331 chainID: big.NewInt(20), 332 signer: types.NewEIP155Signer(big.NewInt(20)), 333 }, 334 { 335 name: "Public Homestead tx", 336 isPrivate: false, 337 chainID: nil, 338 signer: types.HomesteadSigner{}, 339 }, 340 { 341 name: "Private tx", 342 isPrivate: true, 343 chainID: nil, 344 signer: types.QuorumPrivateTxSigner{}, 345 }, 346 } 347 348 toSign := types.NewTransaction( 349 1, 350 common.HexToAddress("0x2332f90a329c2c55ba120b1449d36a144d1f9fe4"), 351 big.NewInt(1), 352 0, 353 big.NewInt(1), 354 nil, 355 ) 356 357 for _, tt := range tests { 358 t.Run(tt.name, func(t *testing.T) { 359 if tt.isPrivate { 360 toSign.SetPrivate() 361 } 362 363 hashToSign := tt.signer.Hash(toSign) 364 365 mockSig := make([]byte, 65) 366 rand.Read(mockSig) 367 368 mockClient := mock_plugin.NewMockService(ctrl) 369 mockClient. 370 EXPECT(). 371 UnlockAndSign(gomock.Any(), acct1, hashToSign.Bytes(), "pwd"). 372 Return(mockSig, nil) 373 374 w := validWallet(mockClient) 375 got, err := w.SignTxWithPassphrase(acct1, "pwd", toSign, tt.chainID) 376 require.NoError(t, err) 377 378 gotV, gotR, gotS := got.RawSignatureValues() 379 380 wantR, wantS, wantV, err := tt.signer.SignatureValues(&types.Transaction{}, mockSig) // tx param is unused by method 381 require.NoError(t, err) 382 383 // assert the correct signature is added to the tx 384 assert.Equal(t, wantV, gotV) 385 assert.Equal(t, wantR, gotR) 386 assert.Equal(t, wantS, gotS) 387 388 // assert the rest of the tx is unchanged 389 assert.Equal(t, toSign.Nonce(), got.Nonce()) 390 assert.Equal(t, toSign.GasPrice(), got.GasPrice()) 391 assert.Equal(t, toSign.Gas(), got.Gas()) 392 assert.Equal(t, toSign.To(), got.To()) 393 assert.Equal(t, toSign.Value(), got.Value()) 394 assert.Equal(t, toSign.Data(), got.Data()) 395 }) 396 } 397 }