소스 검색

accounts/abi: remove check for len%32==0 when unpacking events (#15670)

This change inlines the logic of bytesAreProper at its sole
callsite, ABI.Unpack, and applies the multiple-of-32 test only in
the case of unpacking methods. Event data is not required to be a
multiple of 32 bytes long.
Bob Glickstein 7 년 전
부모
커밋
e21aa0fda3
3개의 변경된 파일47개의 추가작업 그리고 13개의 파일을 삭제
  1. 6 2
      accounts/abi/abi.go
  2. 41 0
      accounts/abi/abi_test.go
  3. 0 11
      accounts/abi/unpack.go

+ 6 - 2
accounts/abi/abi.go

@@ -74,13 +74,17 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
 
 // Unpack output in v according to the abi specification
 func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) {
-	if err = bytesAreProper(output); err != nil {
-		return err
+	if len(output) == 0 {
+		return fmt.Errorf("abi: unmarshalling empty output")
 	}
+
 	// since there can't be naming collisions with contracts and events,
 	// we need to decide whether we're calling a method or an event
 	var unpack unpacker
 	if method, ok := abi.Methods[name]; ok {
+		if len(output)%32 != 0 {
+			return fmt.Errorf("abi: improperly formatted output")
+		}
 		unpack = method
 	} else if event, ok := abi.Events[name]; ok {
 		unpack = event

+ 41 - 0
accounts/abi/abi_test.go

@@ -18,6 +18,7 @@ package abi
 
 import (
 	"bytes"
+	"encoding/hex"
 	"fmt"
 	"log"
 	"math/big"
@@ -418,3 +419,43 @@ func TestBareEvents(t *testing.T) {
 		}
 	}
 }
+
+// TestUnpackEvent is based on this contract:
+//    contract T {
+//      event received(address sender, uint amount, bytes memo);
+//      function receive(bytes memo) external payable {
+//        received(msg.sender, msg.value, memo);
+//      }
+//    }
+// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
+//   receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
+func TestUnpackEvent(t *testing.T) {
+	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"}]`
+	abi, err := JSON(strings.NewReader(abiJSON))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	const hexdata = `000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158`
+	data, err := hex.DecodeString(hexdata)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(data)%32 == 0 {
+		t.Errorf("len(data) is %d, want a non-multiple of 32", len(data))
+	}
+
+	type ReceivedEvent struct {
+		Address common.Address
+		Amount  *big.Int
+		Memo    []byte
+	}
+	var ev ReceivedEvent
+
+	err = abi.Unpack(&ev, "received", data)
+	if err != nil {
+		t.Error(err)
+	} else {
+		t.Logf("len(data): %d; received event: %+v", len(data), ev)
+	}
+}

+ 0 - 11
accounts/abi/unpack.go

@@ -203,14 +203,3 @@ func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err
 	//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
 	return
 }
-
-// checks for proper formatting of byte output
-func bytesAreProper(output []byte) error {
-	if len(output) == 0 {
-		return fmt.Errorf("abi: unmarshalling empty output")
-	} else if len(output)%32 != 0 {
-		return fmt.Errorf("abi: improperly formatted output")
-	} else {
-		return nil
-	}
-}