github.com/trezor/blockbook@v0.4.1-0.20240328132726-e9a08582ee2c/bchain/coins/eth/ethparser_test.go (about) 1 //go:build unittest 2 3 package eth 4 5 import ( 6 "encoding/hex" 7 "fmt" 8 "math/big" 9 "reflect" 10 "testing" 11 12 "github.com/trezor/blockbook/bchain" 13 "github.com/trezor/blockbook/tests/dbtestdata" 14 ) 15 16 func TestEthParser_GetAddrDescFromAddress(t *testing.T) { 17 type args struct { 18 address string 19 } 20 tests := []struct { 21 name string 22 args args 23 want string 24 wantErr bool 25 }{ 26 { 27 name: "with 0x prefix", 28 args: args{address: "0x81b7e08f65bdf5648606c89998a9cc8164397647"}, 29 want: "81b7e08f65bdf5648606c89998a9cc8164397647", 30 }, 31 { 32 name: "without 0x prefix", 33 args: args{address: "47526228d673e9f079630d6cdaff5a2ed13e0e60"}, 34 want: "47526228d673e9f079630d6cdaff5a2ed13e0e60", 35 }, 36 { 37 name: "address of wrong length", 38 args: args{address: "7526228d673e9f079630d6cdaff5a2ed13e0e60"}, 39 want: "", 40 wantErr: true, 41 }, 42 { 43 name: "ErrAddressMissing", 44 args: args{address: ""}, 45 want: "", 46 wantErr: true, 47 }, 48 { 49 name: "error - not eth address", 50 args: args{address: "1JKgN43B9SyLuZH19H5ECvr4KcfrbVHzZ6"}, 51 want: "", 52 wantErr: true, 53 }, 54 } 55 for _, tt := range tests { 56 t.Run(tt.name, func(t *testing.T) { 57 p := NewEthereumParser(1, false) 58 got, err := p.GetAddrDescFromAddress(tt.args.address) 59 if (err != nil) != tt.wantErr { 60 t.Errorf("EthParser.GetAddrDescFromAddress() error = %v, wantErr %v", err, tt.wantErr) 61 return 62 } 63 h := hex.EncodeToString(got) 64 if !reflect.DeepEqual(h, tt.want) { 65 t.Errorf("EthParser.GetAddrDescFromAddress() = %v, want %v", h, tt.want) 66 } 67 }) 68 } 69 } 70 71 var testTx1, testTx2, testTx1Failed, testTx1NoStatus bchain.Tx 72 73 func init() { 74 75 testTx1 = bchain.Tx{ 76 Blocktime: 1534858022, 77 Time: 1534858022, 78 Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 79 Vin: []bchain.Vin{ 80 { 81 Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"}, 82 }, 83 }, 84 Vout: []bchain.Vout{ 85 { 86 ValueSat: *big.NewInt(1999622000000000000), 87 ScriptPubKey: bchain.ScriptPubKey{ 88 Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"}, 89 }, 90 }, 91 }, 92 CoinSpecificData: bchain.EthereumSpecificData{ 93 Tx: &bchain.RpcTransaction{ 94 AccountNonce: "0xb26c", 95 GasPrice: "0x430e23400", 96 GasLimit: "0x5208", 97 To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f", 98 Value: "0x1bc0159d530e6000", 99 Payload: "0x", 100 Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 101 BlockNumber: "0x41eee8", 102 From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97", 103 TransactionIndex: "0xa", 104 }, 105 Receipt: &bchain.RpcReceipt{ 106 GasUsed: "0x5208", 107 Status: "0x1", 108 Logs: []*bchain.RpcLog{}, 109 }, 110 }, 111 } 112 113 testTx2 = bchain.Tx{ 114 Blocktime: 1534858022, 115 Time: 1534858022, 116 Txid: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101", 117 Vin: []bchain.Vin{ 118 { 119 Addresses: []string{"0x20cD153de35D469BA46127A0C8F18626b59a256A"}, 120 }, 121 }, 122 Vout: []bchain.Vout{ 123 { 124 ValueSat: *big.NewInt(0), 125 ScriptPubKey: bchain.ScriptPubKey{ 126 Addresses: []string{"0x4af4114F73d1c1C903aC9E0361b379D1291808A2"}, 127 }, 128 }, 129 }, 130 CoinSpecificData: bchain.EthereumSpecificData{ 131 Tx: &bchain.RpcTransaction{ 132 AccountNonce: "0xd0", 133 GasPrice: "0x9502f9000", 134 GasLimit: "0x130d5", 135 To: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2", 136 Value: "0x0", 137 Payload: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000", 138 Hash: "0xa9cd088aba2131000da6f38a33c20169baee476218deea6b78720700b895b101", 139 BlockNumber: "0x41eee8", 140 From: "0x20cD153de35D469BA46127A0C8F18626b59a256A", 141 TransactionIndex: "0x0"}, 142 Receipt: &bchain.RpcReceipt{ 143 GasUsed: "0xcb39", 144 Status: "0x1", 145 Logs: []*bchain.RpcLog{ 146 { 147 Address: "0x4af4114F73d1c1C903aC9E0361b379D1291808A2", 148 Data: "0x00000000000000000000000000000000000000000000021e19e0c9bab2400000", 149 Topics: []string{ 150 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", 151 "0x00000000000000000000000020cd153de35d469ba46127a0c8f18626b59a256a", 152 "0x000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f", 153 }, 154 }, 155 }, 156 }, 157 }, 158 } 159 160 testTx1Failed = bchain.Tx{ 161 Blocktime: 1534858022, 162 Time: 1534858022, 163 Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 164 Vin: []bchain.Vin{ 165 { 166 Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"}, 167 }, 168 }, 169 Vout: []bchain.Vout{ 170 { 171 ValueSat: *big.NewInt(1999622000000000000), 172 ScriptPubKey: bchain.ScriptPubKey{ 173 Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"}, 174 }, 175 }, 176 }, 177 CoinSpecificData: bchain.EthereumSpecificData{ 178 Tx: &bchain.RpcTransaction{ 179 AccountNonce: "0xb26c", 180 GasPrice: "0x430e23400", 181 GasLimit: "0x5208", 182 To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f", 183 Value: "0x1bc0159d530e6000", 184 Payload: "0x", 185 Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 186 BlockNumber: "0x41eee8", 187 From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97", 188 TransactionIndex: "0xa", 189 }, 190 Receipt: &bchain.RpcReceipt{ 191 GasUsed: "0x5208", 192 Status: "0x0", 193 Logs: []*bchain.RpcLog{}, 194 }, 195 }, 196 } 197 198 testTx1NoStatus = bchain.Tx{ 199 Blocktime: 1534858022, 200 Time: 1534858022, 201 Txid: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 202 Vin: []bchain.Vin{ 203 { 204 Addresses: []string{"0x3E3a3D69dc66bA10737F531ed088954a9EC89d97"}, 205 }, 206 }, 207 Vout: []bchain.Vout{ 208 { 209 ValueSat: *big.NewInt(1999622000000000000), 210 ScriptPubKey: bchain.ScriptPubKey{ 211 Addresses: []string{"0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f"}, 212 }, 213 }, 214 }, 215 CoinSpecificData: bchain.EthereumSpecificData{ 216 Tx: &bchain.RpcTransaction{ 217 AccountNonce: "0xb26c", 218 GasPrice: "0x430e23400", 219 GasLimit: "0x5208", 220 To: "0x555Ee11FBDDc0E49A9bAB358A8941AD95fFDB48f", 221 Value: "0x1bc0159d530e6000", 222 Payload: "0x", 223 Hash: "0xcd647151552b5132b2aef7c9be00dc6f73afc5901dde157aab131335baaa853b", 224 BlockNumber: "0x41eee8", 225 From: "0x3E3a3D69dc66bA10737F531ed088954a9EC89d97", 226 TransactionIndex: "0xa", 227 }, 228 Receipt: &bchain.RpcReceipt{ 229 GasUsed: "0x5208", 230 Status: "", 231 Logs: []*bchain.RpcLog{}, 232 }, 233 }, 234 } 235 236 } 237 238 func TestEthereumParser_PackTx(t *testing.T) { 239 type args struct { 240 tx *bchain.Tx 241 height uint32 242 blockTime int64 243 } 244 tests := []struct { 245 name string 246 p *EthereumParser 247 args args 248 want string 249 wantErr bool 250 }{ 251 { 252 name: "1", 253 args: args{ 254 tx: &testTx1, 255 height: 4321000, 256 blockTime: 1534858022, 257 }, 258 want: dbtestdata.EthTx1Packed, 259 }, 260 { 261 name: "2", 262 args: args{ 263 tx: &testTx2, 264 height: 4321000, 265 blockTime: 1534858022, 266 }, 267 want: dbtestdata.EthTx2Packed, 268 }, 269 { 270 name: "3", 271 args: args{ 272 tx: &testTx1Failed, 273 height: 4321000, 274 blockTime: 1534858022, 275 }, 276 want: dbtestdata.EthTx1FailedPacked, 277 }, 278 { 279 name: "4", 280 args: args{ 281 tx: &testTx1NoStatus, 282 height: 4321000, 283 blockTime: 1534858022, 284 }, 285 want: dbtestdata.EthTx1NoStatusPacked, 286 }, 287 } 288 p := NewEthereumParser(1, false) 289 for _, tt := range tests { 290 t.Run(tt.name, func(t *testing.T) { 291 got, err := p.PackTx(tt.args.tx, tt.args.height, tt.args.blockTime) 292 if (err != nil) != tt.wantErr { 293 t.Errorf("EthereumParser.PackTx() error = %v, wantErr %v", err, tt.wantErr) 294 return 295 } 296 h := hex.EncodeToString(got) 297 if !reflect.DeepEqual(h, tt.want) { 298 t.Errorf("EthereumParser.PackTx() = %v, want %v", h, tt.want) 299 } 300 }) 301 } 302 } 303 304 func TestEthereumParser_UnpackTx(t *testing.T) { 305 type args struct { 306 hex string 307 } 308 tests := []struct { 309 name string 310 p *EthereumParser 311 args args 312 want *bchain.Tx 313 want1 uint32 314 wantErr bool 315 }{ 316 { 317 name: "1", 318 args: args{hex: dbtestdata.EthTx1Packed}, 319 want: &testTx1, 320 want1: 4321000, 321 }, 322 { 323 name: "2", 324 args: args{hex: dbtestdata.EthTx2Packed}, 325 want: &testTx2, 326 want1: 4321000, 327 }, 328 { 329 name: "3", 330 args: args{hex: dbtestdata.EthTx1FailedPacked}, 331 want: &testTx1Failed, 332 want1: 4321000, 333 }, 334 { 335 name: "4", 336 args: args{hex: dbtestdata.EthTx1NoStatusPacked}, 337 want: &testTx1NoStatus, 338 want1: 4321000, 339 }, 340 } 341 p := NewEthereumParser(1, false) 342 for _, tt := range tests { 343 t.Run(tt.name, func(t *testing.T) { 344 b, err := hex.DecodeString(tt.args.hex) 345 if err != nil { 346 panic(err) 347 } 348 got, got1, err := p.UnpackTx(b) 349 if (err != nil) != tt.wantErr { 350 t.Errorf("EthereumParser.UnpackTx() error = %v, wantErr %v", err, tt.wantErr) 351 return 352 } 353 // DeepEqual has problems with pointers in completeTransaction 354 gs := got.CoinSpecificData.(bchain.EthereumSpecificData) 355 ws := tt.want.CoinSpecificData.(bchain.EthereumSpecificData) 356 gc := *got 357 wc := *tt.want 358 gc.CoinSpecificData = nil 359 wc.CoinSpecificData = nil 360 if fmt.Sprint(gc) != fmt.Sprint(wc) { 361 // if !reflect.DeepEqual(gc, wc) { 362 t.Errorf("EthereumParser.UnpackTx() gc got = %+v, want %+v", gc, wc) 363 } 364 if !reflect.DeepEqual(gs.Tx, ws.Tx) { 365 t.Errorf("EthereumParser.UnpackTx() gs.Tx got = %+v, want %+v", gs.Tx, ws.Tx) 366 } 367 if !reflect.DeepEqual(gs.Receipt, ws.Receipt) { 368 t.Errorf("EthereumParser.UnpackTx() gs.Receipt got = %+v, want %+v", gs.Receipt, ws.Receipt) 369 } 370 if got1 != tt.want1 { 371 t.Errorf("EthereumParser.UnpackTx() got1 = %v, want %v", got1, tt.want1) 372 } 373 }) 374 } 375 } 376 377 func TestEthereumParser_GetEthereumTxData(t *testing.T) { 378 tests := []struct { 379 name string 380 tx *bchain.Tx 381 want string 382 }{ 383 { 384 name: "Test empty data", 385 tx: &testTx1, 386 want: "0x", 387 }, 388 { 389 name: "Test non empty data", 390 tx: &testTx2, 391 want: "0xa9059cbb000000000000000000000000555ee11fbddc0e49a9bab358a8941ad95ffdb48f00000000000000000000000000000000000000000000021e19e0c9bab2400000", 392 }, 393 } 394 for _, tt := range tests { 395 t.Run(tt.name, func(t *testing.T) { 396 got := GetEthereumTxData(tt.tx) 397 if got.Data != tt.want { 398 t.Errorf("EthereumParser.GetEthereumTxData() = %v, want %v", got.Data, tt.want) 399 } 400 }) 401 } 402 } 403 404 func TestEthereumParser_ParseErrorFromOutput(t *testing.T) { 405 tests := []struct { 406 name string 407 output string 408 want string 409 }{ 410 { 411 name: "ParseErrorFromOutput 1", 412 output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000031546f74616c206e756d626572206f662067726f757073206d7573742062652067726561746572207468616e207a65726f2e000000000000000000000000000000", 413 want: "Total number of groups must be greater than zero.", 414 }, 415 { 416 name: "ParseErrorFromOutput 2", 417 output: "0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000", 418 want: "not enough balance", 419 }, 420 { 421 name: "ParseErrorFromOutput empty", 422 output: "", 423 want: "", 424 }, 425 { 426 name: "ParseErrorFromOutput short", 427 output: "0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012", 428 want: "", 429 }, 430 { 431 name: "ParseErrorFromOutput invalid signature", 432 output: "0x08c379b0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000126e6f7420656e6f7567682062616c616e63650000000000000000000000000000", 433 want: "", 434 }, 435 } 436 for _, tt := range tests { 437 t.Run(tt.name, func(t *testing.T) { 438 got := ParseErrorFromOutput(tt.output) 439 if got != tt.want { 440 t.Errorf("EthereumParser.ParseErrorFromOutput() = %v, want %v", got, tt.want) 441 } 442 }) 443 } 444 } 445 446 func TestEthereumParser_PackInternalTransactionError_UnpackInternalTransactionError(t *testing.T) { 447 tests := []struct { 448 name string 449 original string 450 packed string 451 unpacked string 452 }{ 453 { 454 name: "execution reverted", 455 original: "execution reverted", 456 packed: "\x01", 457 unpacked: "Reverted.", 458 }, 459 { 460 name: "out of gas", 461 original: "out of gas", 462 packed: "\x02", 463 unpacked: "Out of gas.", 464 }, 465 { 466 name: "contract creation code storage out of gas", 467 original: "contract creation code storage out of gas", 468 packed: "\x03", 469 unpacked: "Contract creation code storage out of gas.", 470 }, 471 { 472 name: "max code size exceeded", 473 original: "max code size exceeded", 474 packed: "\x04", 475 unpacked: "Max code size exceeded.", 476 }, 477 { 478 name: "unknown error", 479 original: "unknown error", 480 packed: "unknown error", 481 unpacked: "unknown error", 482 }, 483 } 484 for _, tt := range tests { 485 t.Run(tt.name, func(t *testing.T) { 486 packed := PackInternalTransactionError(tt.original) 487 if packed != tt.packed { 488 t.Errorf("EthereumParser.PackInternalTransactionError() = %v, want %v", packed, tt.packed) 489 } 490 unpacked := UnpackInternalTransactionError([]byte(packed)) 491 if unpacked != tt.unpacked { 492 t.Errorf("EthereumParser.UnpackInternalTransactionError() = %v, want %v", unpacked, tt.unpacked) 493 } 494 }) 495 } 496 }