Skip to content

Commit 933972d

Browse files
authored
Merge pull request #16256 from epiclabs-io/unpack_one_arg_event
Fix issue unmarshaling single parameter events from abigen generated go code #16208
2 parents b1917ac + 60a999f commit 933972d

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-19
lines changed

accounts/abi/abi_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,14 +621,16 @@ func TestBareEvents(t *testing.T) {
621621
// TestUnpackEvent is based on this contract:
622622
// contract T {
623623
// event received(address sender, uint amount, bytes memo);
624+
// event receivedAddr(address sender);
624625
// function receive(bytes memo) external payable {
625626
// received(msg.sender, msg.value, memo);
627+
// receivedAddr(msg.sender);
626628
// }
627629
// }
628630
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
629631
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
630632
func TestUnpackEvent(t *testing.T) {
631-
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"}]`
633+
const abiJSON = `[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
632634
abi, err := JSON(strings.NewReader(abiJSON))
633635
if err != nil {
634636
t.Fatal(err)
@@ -656,6 +658,17 @@ func TestUnpackEvent(t *testing.T) {
656658
} else {
657659
t.Logf("len(data): %d; received event: %+v", len(data), ev)
658660
}
661+
662+
type ReceivedAddrEvent struct {
663+
Address common.Address
664+
}
665+
var receivedAddrEv ReceivedAddrEvent
666+
err = abi.Unpack(&receivedAddrEv, "receivedAddr", data)
667+
if err != nil {
668+
t.Error(err)
669+
} else {
670+
t.Logf("len(data): %d; received event: %+v", len(data), receivedAddrEv)
671+
}
659672
}
660673

661674
func TestABI_MethodById(t *testing.T) {

accounts/abi/argument.go

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,8 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
113113
}
114114
// If the output interface is a struct, make sure names don't collide
115115
if kind == reflect.Struct {
116-
exists := make(map[string]bool)
117-
for _, arg := range arguments {
118-
field := capitalise(arg.Name)
119-
if field == "" {
120-
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
121-
}
122-
if exists[field] {
123-
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
124-
}
125-
exists[field] = true
116+
if err := requireUniqueStructFieldNames(arguments); err != nil {
117+
return err
126118
}
127119
}
128120
for i, arg := range arguments.NonIndexed() {
@@ -131,14 +123,9 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
131123

132124
switch kind {
133125
case reflect.Struct:
134-
name := capitalise(arg.Name)
135-
for j := 0; j < typ.NumField(); j++ {
136-
// TODO read tags: `abi:"fieldName"`
137-
if typ.Field(j).Name == name {
138-
if err := set(value.Field(j), reflectValue, arg); err != nil {
139-
return err
140-
}
141-
}
126+
err := unpackStruct(value, reflectValue, arg)
127+
if err != nil {
128+
return err
142129
}
143130
case reflect.Slice, reflect.Array:
144131
if value.Len() < i {
@@ -165,8 +152,20 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf
165152
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
166153
}
167154
elem := reflect.ValueOf(v).Elem()
155+
kind := elem.Kind()
168156
reflectValue := reflect.ValueOf(marshalledValues[0])
157+
158+
if kind == reflect.Struct {
159+
//make sure names don't collide
160+
if err := requireUniqueStructFieldNames(arguments); err != nil {
161+
return err
162+
}
163+
164+
return unpackStruct(elem, reflectValue, arguments[0])
165+
}
166+
169167
return set(elem, reflectValue, arguments.NonIndexed()[0])
168+
170169
}
171170

172171
// Computes the full size of an array;
@@ -278,3 +277,18 @@ func capitalise(input string) string {
278277
}
279278
return strings.ToUpper(input[:1]) + input[1:]
280279
}
280+
281+
//unpackStruct extracts each argument into its corresponding struct field
282+
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
283+
name := capitalise(arg.Name)
284+
typ := value.Type()
285+
for j := 0; j < typ.NumField(); j++ {
286+
// TODO read tags: `abi:"fieldName"`
287+
if typ.Field(j).Name == name {
288+
if err := set(value.Field(j), reflectValue, arg); err != nil {
289+
return err
290+
}
291+
}
292+
}
293+
return nil
294+
}

accounts/abi/reflect.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
110110
}
111111
return nil
112112
}
113+
114+
// requireUniqueStructFieldNames makes sure field names don't collide
115+
func requireUniqueStructFieldNames(args Arguments) error {
116+
exists := make(map[string]bool)
117+
for _, arg := range args {
118+
field := capitalise(arg.Name)
119+
if field == "" {
120+
return fmt.Errorf("abi: purely underscored output cannot unpack to struct")
121+
}
122+
if exists[field] {
123+
return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field)
124+
}
125+
exists[field] = true
126+
}
127+
return nil
128+
}

0 commit comments

Comments
 (0)