github.com/klaytn/klaytn@v1.10.2/accounts/abi/event_test.go (about)

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