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  }