github.com/ava-labs/subnet-evm@v0.6.4/accounts/abi/event_test.go (about)

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