github.com/luckypickle/go-ethereum-vet@v1.14.2/accounts/abi/event_test.go (about) 1 // Copyright 2016 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 abi 18 19 import ( 20 "bytes" 21 "encoding/hex" 22 "encoding/json" 23 "math/big" 24 "reflect" 25 "strings" 26 "testing" 27 28 "github.com/luckypickle/go-ethereum-vet/common" 29 "github.com/luckypickle/go-ethereum-vet/crypto" 30 "github.com/stretchr/testify/assert" 31 "github.com/stretchr/testify/require" 32 ) 33 34 var jsonEventTransfer = []byte(`{ 35 "anonymous": false, 36 "inputs": [ 37 { 38 "indexed": true, "name": "from", "type": "address" 39 }, { 40 "indexed": true, "name": "to", "type": "address" 41 }, { 42 "indexed": false, "name": "value", "type": "uint256" 43 }], 44 "name": "Transfer", 45 "type": "event" 46 }`) 47 48 var jsonEventPledge = []byte(`{ 49 "anonymous": false, 50 "inputs": [{ 51 "indexed": false, "name": "who", "type": "address" 52 }, { 53 "indexed": false, "name": "wad", "type": "uint128" 54 }, { 55 "indexed": false, "name": "currency", "type": "bytes3" 56 }], 57 "name": "Pledge", 58 "type": "event" 59 }`) 60 61 var jsonEventMixedCase = []byte(`{ 62 "anonymous": false, 63 "inputs": [{ 64 "indexed": false, "name": "value", "type": "uint256" 65 }, { 66 "indexed": false, "name": "_value", "type": "uint256" 67 }, { 68 "indexed": false, "name": "Value", "type": "uint256" 69 }], 70 "name": "MixedCase", 71 "type": "event" 72 }`) 73 74 // 1000000 75 var transferData1 = "00000000000000000000000000000000000000000000000000000000000f4240" 76 77 // "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd" 78 var pledgeData1 = "00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000" 79 80 // 1000000,2218516807680,1000001 81 var mixedCaseData1 = "00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241" 82 83 func TestEventId(t *testing.T) { 84 var table = []struct { 85 definition string 86 expectations map[string]common.Hash 87 }{ 88 { 89 definition: `[ 90 { "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, 91 { "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } 92 ]`, 93 expectations: map[string]common.Hash{ 94 "balance": crypto.Keccak256Hash([]byte("balance(uint256)")), 95 "check": crypto.Keccak256Hash([]byte("check(address,uint256)")), 96 }, 97 }, 98 } 99 100 for _, test := range table { 101 abi, err := JSON(strings.NewReader(test.definition)) 102 if err != nil { 103 t.Fatal(err) 104 } 105 106 for name, event := range abi.Events { 107 if event.Id() != test.expectations[name] { 108 t.Errorf("expected id to be %x, got %x", test.expectations[name], event.Id()) 109 } 110 } 111 } 112 } 113 114 // TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array. 115 func TestEventMultiValueWithArrayUnpack(t *testing.T) { 116 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` 117 type testStruct struct { 118 Value1 [2]uint8 119 Value2 uint8 120 } 121 abi, err := JSON(strings.NewReader(definition)) 122 require.NoError(t, err) 123 var b bytes.Buffer 124 var i uint8 = 1 125 for ; i <= 3; i++ { 126 b.Write(packNum(reflect.ValueOf(i))) 127 } 128 var rst testStruct 129 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 130 require.Equal(t, [2]uint8{1, 2}, rst.Value1) 131 require.Equal(t, uint8(3), rst.Value2) 132 } 133 134 func TestEventTupleUnpack(t *testing.T) { 135 136 type EventTransfer struct { 137 Value *big.Int 138 } 139 140 type EventTransferWithTag struct { 141 // this is valid because `value` is not exportable, 142 // so value is only unmarshalled into `Value1`. 143 value *big.Int 144 Value1 *big.Int `abi:"value"` 145 } 146 147 type BadEventTransferWithSameFieldAndTag struct { 148 Value *big.Int 149 Value1 *big.Int `abi:"value"` 150 } 151 152 type BadEventTransferWithDuplicatedTag struct { 153 Value1 *big.Int `abi:"value"` 154 Value2 *big.Int `abi:"value"` 155 } 156 157 type BadEventTransferWithEmptyTag struct { 158 Value *big.Int `abi:""` 159 } 160 161 type EventPledge struct { 162 Who common.Address 163 Wad *big.Int 164 Currency [3]byte 165 } 166 167 type BadEventPledge struct { 168 Who string 169 Wad int 170 Currency [3]byte 171 } 172 173 type EventMixedCase struct { 174 Value1 *big.Int `abi:"value"` 175 Value2 *big.Int `abi:"_value"` 176 Value3 *big.Int `abi:"Value"` 177 } 178 179 bigint := new(big.Int) 180 bigintExpected := big.NewInt(1000000) 181 bigintExpected2 := big.NewInt(2218516807680) 182 bigintExpected3 := big.NewInt(1000001) 183 addr := common.HexToAddress("0x00Ce0d46d924CC8437c806721496599FC3FFA268") 184 var testCases = []struct { 185 data string 186 dest interface{} 187 expected interface{} 188 jsonLog []byte 189 error string 190 name string 191 }{{ 192 transferData1, 193 &EventTransfer{}, 194 &EventTransfer{Value: bigintExpected}, 195 jsonEventTransfer, 196 "", 197 "Can unpack ERC20 Transfer event into structure", 198 }, { 199 transferData1, 200 &[]interface{}{&bigint}, 201 &[]interface{}{&bigintExpected}, 202 jsonEventTransfer, 203 "", 204 "Can unpack ERC20 Transfer event into slice", 205 }, { 206 transferData1, 207 &EventTransferWithTag{}, 208 &EventTransferWithTag{Value1: bigintExpected}, 209 jsonEventTransfer, 210 "", 211 "Can unpack ERC20 Transfer event into structure with abi: tag", 212 }, { 213 transferData1, 214 &BadEventTransferWithDuplicatedTag{}, 215 &BadEventTransferWithDuplicatedTag{}, 216 jsonEventTransfer, 217 "struct: abi tag in 'Value2' already mapped", 218 "Can not unpack ERC20 Transfer event with duplicated abi tag", 219 }, { 220 transferData1, 221 &BadEventTransferWithSameFieldAndTag{}, 222 &BadEventTransferWithSameFieldAndTag{}, 223 jsonEventTransfer, 224 "abi: multiple variables maps to the same abi field 'value'", 225 "Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable", 226 }, { 227 transferData1, 228 &BadEventTransferWithEmptyTag{}, 229 &BadEventTransferWithEmptyTag{}, 230 jsonEventTransfer, 231 "struct: abi tag in 'Value' is empty", 232 "Can not unpack ERC20 Transfer event with an empty tag", 233 }, { 234 pledgeData1, 235 &EventPledge{}, 236 &EventPledge{ 237 addr, 238 bigintExpected2, 239 [3]byte{'u', 's', 'd'}}, 240 jsonEventPledge, 241 "", 242 "Can unpack Pledge event into structure", 243 }, { 244 pledgeData1, 245 &[]interface{}{&common.Address{}, &bigint, &[3]byte{}}, 246 &[]interface{}{ 247 &addr, 248 &bigintExpected2, 249 &[3]byte{'u', 's', 'd'}}, 250 jsonEventPledge, 251 "", 252 "Can unpack Pledge event into slice", 253 }, { 254 pledgeData1, 255 &[3]interface{}{&common.Address{}, &bigint, &[3]byte{}}, 256 &[3]interface{}{ 257 &addr, 258 &bigintExpected2, 259 &[3]byte{'u', 's', 'd'}}, 260 jsonEventPledge, 261 "", 262 "Can unpack Pledge event into an array", 263 }, { 264 pledgeData1, 265 &[]interface{}{new(int), 0, 0}, 266 &[]interface{}{}, 267 jsonEventPledge, 268 "abi: cannot unmarshal common.Address in to int", 269 "Can not unpack Pledge event into slice with wrong types", 270 }, { 271 pledgeData1, 272 &BadEventPledge{}, 273 &BadEventPledge{}, 274 jsonEventPledge, 275 "abi: cannot unmarshal common.Address in to string", 276 "Can not unpack Pledge event into struct with wrong filed types", 277 }, { 278 pledgeData1, 279 &[]interface{}{common.Address{}, new(big.Int)}, 280 &[]interface{}{}, 281 jsonEventPledge, 282 "abi: insufficient number of elements in the list/array for unpack, want 3, got 2", 283 "Can not unpack Pledge event into too short slice", 284 }, { 285 pledgeData1, 286 new(map[string]interface{}), 287 &[]interface{}{}, 288 jsonEventPledge, 289 "abi: cannot unmarshal tuple into map[string]interface {}", 290 "Can not unpack Pledge event into map", 291 }, { 292 mixedCaseData1, 293 &EventMixedCase{}, 294 &EventMixedCase{Value1: bigintExpected, Value2: bigintExpected2, Value3: bigintExpected3}, 295 jsonEventMixedCase, 296 "", 297 "Can unpack abi variables with mixed case", 298 }} 299 300 for _, tc := range testCases { 301 assert := assert.New(t) 302 tc := tc 303 t.Run(tc.name, func(t *testing.T) { 304 err := unpackTestEventData(tc.dest, tc.data, tc.jsonLog, assert) 305 if tc.error == "" { 306 assert.Nil(err, "Should be able to unpack event data.") 307 assert.Equal(tc.expected, tc.dest, tc.name) 308 } else { 309 assert.EqualError(err, tc.error, tc.name) 310 } 311 }) 312 } 313 } 314 315 func unpackTestEventData(dest interface{}, hexData string, jsonEvent []byte, assert *assert.Assertions) error { 316 data, err := hex.DecodeString(hexData) 317 assert.NoError(err, "Hex data should be a correct hex-string") 318 var e Event 319 assert.NoError(json.Unmarshal(jsonEvent, &e), "Should be able to unmarshal event ABI") 320 a := ABI{Events: map[string]Event{"e": e}} 321 return a.Unpack(dest, "e", data) 322 } 323 324 /* 325 Taken from 326 https://github.com/luckypickle/go-ethereum-vet/pull/15568 327 */ 328 329 type testResult struct { 330 Values [2]*big.Int 331 Value1 *big.Int 332 Value2 *big.Int 333 } 334 335 type testCase struct { 336 definition string 337 want testResult 338 } 339 340 func (tc testCase) encoded(intType, arrayType Type) []byte { 341 var b bytes.Buffer 342 if tc.want.Value1 != nil { 343 val, _ := intType.pack(reflect.ValueOf(tc.want.Value1)) 344 b.Write(val) 345 } 346 347 if !reflect.DeepEqual(tc.want.Values, [2]*big.Int{nil, nil}) { 348 val, _ := arrayType.pack(reflect.ValueOf(tc.want.Values)) 349 b.Write(val) 350 } 351 if tc.want.Value2 != nil { 352 val, _ := intType.pack(reflect.ValueOf(tc.want.Value2)) 353 b.Write(val) 354 } 355 return b.Bytes() 356 } 357 358 // TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder. 359 func TestEventUnpackIndexed(t *testing.T) { 360 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` 361 type testStruct struct { 362 Value1 uint8 363 Value2 uint8 364 } 365 abi, err := JSON(strings.NewReader(definition)) 366 require.NoError(t, err) 367 var b bytes.Buffer 368 b.Write(packNum(reflect.ValueOf(uint8(8)))) 369 var rst testStruct 370 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 371 require.Equal(t, uint8(0), rst.Value1) 372 require.Equal(t, uint8(8), rst.Value2) 373 } 374 375 // TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input. 376 func TestEventIndexedWithArrayUnpack(t *testing.T) { 377 definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]` 378 type testStruct struct { 379 Value1 [2]uint8 380 Value2 string 381 } 382 abi, err := JSON(strings.NewReader(definition)) 383 require.NoError(t, err) 384 var b bytes.Buffer 385 stringOut := "abc" 386 // number of fields that will be encoded * 32 387 b.Write(packNum(reflect.ValueOf(32))) 388 b.Write(packNum(reflect.ValueOf(len(stringOut)))) 389 b.Write(common.RightPadBytes([]byte(stringOut), 32)) 390 391 var rst testStruct 392 require.NoError(t, abi.Unpack(&rst, "test", b.Bytes())) 393 require.Equal(t, [2]uint8{0, 0}, rst.Value1) 394 require.Equal(t, stringOut, rst.Value2) 395 }