gitlab.com/yannislg/go-pulse@v0.0.0-20210722055913-a3e24e95638d/accounts/abi/bind/topics_test.go (about)

     1  // Copyright 2019 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package bind
    18  
    19  import (
    20  	"math/big"
    21  	"reflect"
    22  	"testing"
    23  
    24  	"github.com/ethereum/go-ethereum/accounts/abi"
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  )
    28  
    29  func TestMakeTopics(t *testing.T) {
    30  	type args struct {
    31  		query [][]interface{}
    32  	}
    33  	tests := []struct {
    34  		name    string
    35  		args    args
    36  		want    [][]common.Hash
    37  		wantErr bool
    38  	}{
    39  		{
    40  			"support fixed byte types, right padded to 32 bytes",
    41  			args{[][]interface{}{{[5]byte{1, 2, 3, 4, 5}}}},
    42  			[][]common.Hash{{common.Hash{1, 2, 3, 4, 5}}},
    43  			false,
    44  		},
    45  		{
    46  			"support common hash types in topics",
    47  			args{[][]interface{}{{common.Hash{1, 2, 3, 4, 5}}}},
    48  			[][]common.Hash{{common.Hash{1, 2, 3, 4, 5}}},
    49  			false,
    50  		},
    51  		{
    52  			"support address types in topics",
    53  			args{[][]interface{}{{common.Address{1, 2, 3, 4, 5}}}},
    54  			[][]common.Hash{{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5}}},
    55  			false,
    56  		},
    57  		{
    58  			"support *big.Int types in topics",
    59  			args{[][]interface{}{{big.NewInt(1).Lsh(big.NewInt(2), 254)}}},
    60  			[][]common.Hash{{common.Hash{128}}},
    61  			false,
    62  		},
    63  		{
    64  			"support boolean types in topics",
    65  			args{[][]interface{}{
    66  				{true},
    67  				{false},
    68  			}},
    69  			[][]common.Hash{
    70  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
    71  				{common.Hash{0}},
    72  			},
    73  			false,
    74  		},
    75  		{
    76  			"support int/uint(8/16/32/64) types in topics",
    77  			args{[][]interface{}{
    78  				{int8(-2)},
    79  				{int16(-3)},
    80  				{int32(-4)},
    81  				{int64(-5)},
    82  				{int8(1)},
    83  				{int16(256)},
    84  				{int32(65536)},
    85  				{int64(4294967296)},
    86  				{uint8(1)},
    87  				{uint16(256)},
    88  				{uint32(65536)},
    89  				{uint64(4294967296)},
    90  			}},
    91  			[][]common.Hash{
    92  				{common.Hash{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254}},
    93  				{common.Hash{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253}},
    94  				{common.Hash{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252}},
    95  				{common.Hash{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251}},
    96  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
    97  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}},
    98  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
    99  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}},
   100  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
   101  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}},
   102  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
   103  				{common.Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0}},
   104  			},
   105  			false,
   106  		},
   107  		{
   108  			"support string types in topics",
   109  			args{[][]interface{}{{"hello world"}}},
   110  			[][]common.Hash{{crypto.Keccak256Hash([]byte("hello world"))}},
   111  			false,
   112  		},
   113  		{
   114  			"support byte slice types in topics",
   115  			args{[][]interface{}{{[]byte{1, 2, 3}}}},
   116  			[][]common.Hash{{crypto.Keccak256Hash([]byte{1, 2, 3})}},
   117  			false,
   118  		},
   119  	}
   120  	for _, tt := range tests {
   121  		t.Run(tt.name, func(t *testing.T) {
   122  			got, err := makeTopics(tt.args.query...)
   123  			if (err != nil) != tt.wantErr {
   124  				t.Errorf("makeTopics() error = %v, wantErr %v", err, tt.wantErr)
   125  				return
   126  			}
   127  			if !reflect.DeepEqual(got, tt.want) {
   128  				t.Errorf("makeTopics() = %v, want %v", got, tt.want)
   129  			}
   130  		})
   131  	}
   132  }
   133  
   134  type args struct {
   135  	createObj func() interface{}
   136  	resultObj func() interface{}
   137  	resultMap func() map[string]interface{}
   138  	fields    abi.Arguments
   139  	topics    []common.Hash
   140  }
   141  
   142  type bytesStruct struct {
   143  	StaticBytes [5]byte
   144  }
   145  type int8Struct struct {
   146  	Int8Value int8
   147  }
   148  type int256Struct struct {
   149  	Int256Value *big.Int
   150  }
   151  
   152  type topicTest struct {
   153  	name    string
   154  	args    args
   155  	wantErr bool
   156  }
   157  
   158  func setupTopicsTests() []topicTest {
   159  	bytesType, _ := abi.NewType("bytes5", "", nil)
   160  	int8Type, _ := abi.NewType("int8", "", nil)
   161  	int256Type, _ := abi.NewType("int256", "", nil)
   162  	tupleType, _ := abi.NewType("tuple(int256,int8)", "", nil)
   163  
   164  	tests := []topicTest{
   165  		{
   166  			name: "support fixed byte types, right padded to 32 bytes",
   167  			args: args{
   168  				createObj: func() interface{} { return &bytesStruct{} },
   169  				resultObj: func() interface{} { return &bytesStruct{StaticBytes: [5]byte{1, 2, 3, 4, 5}} },
   170  				resultMap: func() map[string]interface{} {
   171  					return map[string]interface{}{"staticBytes": [5]byte{1, 2, 3, 4, 5}}
   172  				},
   173  				fields: abi.Arguments{abi.Argument{
   174  					Name:    "staticBytes",
   175  					Type:    bytesType,
   176  					Indexed: true,
   177  				}},
   178  				topics: []common.Hash{
   179  					{1, 2, 3, 4, 5},
   180  				},
   181  			},
   182  			wantErr: false,
   183  		},
   184  		{
   185  			name: "int8 with negative value",
   186  			args: args{
   187  				createObj: func() interface{} { return &int8Struct{} },
   188  				resultObj: func() interface{} { return &int8Struct{Int8Value: -1} },
   189  				resultMap: func() map[string]interface{} {
   190  					return map[string]interface{}{"int8Value": int8(-1)}
   191  				},
   192  				fields: abi.Arguments{abi.Argument{
   193  					Name:    "int8Value",
   194  					Type:    int8Type,
   195  					Indexed: true,
   196  				}},
   197  				topics: []common.Hash{
   198  					{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   199  						255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
   200  				},
   201  			},
   202  			wantErr: false,
   203  		},
   204  		{
   205  			name: "int256 with negative value",
   206  			args: args{
   207  				createObj: func() interface{} { return &int256Struct{} },
   208  				resultObj: func() interface{} { return &int256Struct{Int256Value: big.NewInt(-1)} },
   209  				resultMap: func() map[string]interface{} {
   210  					return map[string]interface{}{"int256Value": big.NewInt(-1)}
   211  				},
   212  				fields: abi.Arguments{abi.Argument{
   213  					Name:    "int256Value",
   214  					Type:    int256Type,
   215  					Indexed: true,
   216  				}},
   217  				topics: []common.Hash{
   218  					{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
   219  						255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
   220  				},
   221  			},
   222  			wantErr: false,
   223  		},
   224  		{
   225  			name: "tuple(int256, int8)",
   226  			args: args{
   227  				createObj: func() interface{} { return nil },
   228  				resultObj: func() interface{} { return nil },
   229  				resultMap: func() map[string]interface{} { return make(map[string]interface{}) },
   230  				fields: abi.Arguments{abi.Argument{
   231  					Name:    "tupletype",
   232  					Type:    tupleType,
   233  					Indexed: true,
   234  				}},
   235  				topics: []common.Hash{},
   236  			},
   237  			wantErr: true,
   238  		},
   239  	}
   240  
   241  	return tests
   242  }
   243  
   244  func TestParseTopics(t *testing.T) {
   245  	tests := setupTopicsTests()
   246  
   247  	for _, tt := range tests {
   248  		t.Run(tt.name, func(t *testing.T) {
   249  			createObj := tt.args.createObj()
   250  			if err := parseTopics(createObj, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
   251  				t.Errorf("parseTopics() error = %v, wantErr %v", err, tt.wantErr)
   252  			}
   253  			resultObj := tt.args.resultObj()
   254  			if !reflect.DeepEqual(createObj, resultObj) {
   255  				t.Errorf("parseTopics() = %v, want %v", createObj, resultObj)
   256  			}
   257  		})
   258  	}
   259  }
   260  
   261  func TestParseTopicsIntoMap(t *testing.T) {
   262  	tests := setupTopicsTests()
   263  
   264  	for _, tt := range tests {
   265  		t.Run(tt.name, func(t *testing.T) {
   266  			outMap := make(map[string]interface{})
   267  			if err := parseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
   268  				t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr)
   269  			}
   270  			resultMap := tt.args.resultMap()
   271  			if !reflect.DeepEqual(outMap, resultMap) {
   272  				t.Errorf("parseTopicsIntoMap() = %v, want %v", outMap, resultMap)
   273  			}
   274  		})
   275  	}
   276  }