Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
dec8bba9
Commit
dec8bba9
authored
Oct 17, 2017
by
RJ Catalano
Committed by
Felix Lange
Oct 17, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts/abi: improve type handling, add event support (#14743)
parent
e9295163
Changes
15
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
903 additions
and
847 deletions
+903
-847
abi.go
accounts/abi/abi.go
+16
-99
abi_test.go
accounts/abi/abi_test.go
+1
-20
bind_test.go
accounts/abi/bind/bind_test.go
+1
-1
error.go
accounts/abi/error.go
+12
-12
event.go
accounts/abi/event.go
+91
-0
event_test.go
accounts/abi/event_test.go
+1
-1
method.go
accounts/abi/method.go
+79
-0
numbers.go
accounts/abi/numbers.go
+17
-30
pack.go
accounts/abi/pack.go
+5
-2
pack_test.go
accounts/abi/pack_test.go
+2
-5
reflect.go
accounts/abi/reflect.go
+2
-8
type.go
accounts/abi/type.go
+103
-107
type_test.go
accounts/abi/type_test.go
+170
-45
unpack.go
accounts/abi/unpack.go
+130
-149
unpack_test.go
accounts/abi/unpack_test.go
+273
-368
No files found.
accounts/abi/abi.go
View file @
dec8bba9
...
...
@@ -20,10 +20,6 @@ import (
"encoding/json"
"fmt"
"io"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/common"
)
// The ABI holds information about a contract's context and available
...
...
@@ -76,106 +72,27 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return
append
(
method
.
Id
(),
arguments
...
),
nil
}
// these variable are used to determine certain types during type assertion for
// assignment.
var
(
r_interSlice
=
reflect
.
TypeOf
([]
interface
{}{})
r_hash
=
reflect
.
TypeOf
(
common
.
Hash
{})
r_bytes
=
reflect
.
TypeOf
([]
byte
{})
r_byte
=
reflect
.
TypeOf
(
byte
(
0
))
)
// Unpack output in v according to the abi specification
func
(
abi
ABI
)
Unpack
(
v
interface
{},
name
string
,
output
[]
byte
)
error
{
var
method
=
abi
.
Methods
[
name
]
if
len
(
output
)
==
0
{
return
fmt
.
Errorf
(
"abi: unmarshalling empty output"
)
}
// make sure the passed value is a pointer
valueOf
:=
reflect
.
ValueOf
(
v
)
if
reflect
.
Ptr
!=
valueOf
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
func
(
abi
ABI
)
Unpack
(
v
interface
{},
name
string
,
output
[]
byte
)
(
err
error
)
{
if
err
=
bytesAreProper
(
output
);
err
!=
nil
{
return
err
}
var
(
value
=
valueOf
.
Elem
()
typ
=
value
.
Type
()
)
if
len
(
method
.
Outputs
)
>
1
{
switch
value
.
Kind
()
{
// struct will match named return values to the struct's field
// names
case
reflect
.
Struct
:
for
i
:=
0
;
i
<
len
(
method
.
Outputs
);
i
++
{
marshalledValue
,
err
:=
toGoType
(
i
,
method
.
Outputs
[
i
],
output
)
if
err
!=
nil
{
return
err
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
for
j
:=
0
;
j
<
typ
.
NumField
();
j
++
{
field
:=
typ
.
Field
(
j
)
// TODO read tags: `abi:"fieldName"`
if
field
.
Name
==
strings
.
ToUpper
(
method
.
Outputs
[
i
]
.
Name
[
:
1
])
+
method
.
Outputs
[
i
]
.
Name
[
1
:
]
{
if
err
:=
set
(
value
.
Field
(
j
),
reflectValue
,
method
.
Outputs
[
i
]);
err
!=
nil
{
return
err
}
}
}
}
case
reflect
.
Slice
:
if
!
value
.
Type
()
.
AssignableTo
(
r_interSlice
)
{
return
fmt
.
Errorf
(
"abi: cannot marshal tuple in to slice %T (only []interface{} is supported)"
,
v
)
}
// if the slice already contains values, set those instead of the interface slice itself.
if
value
.
Len
()
>
0
{
if
len
(
method
.
Outputs
)
>
value
.
Len
()
{
return
fmt
.
Errorf
(
"abi: cannot marshal in to slices of unequal size (require: %v, got: %v)"
,
len
(
method
.
Outputs
),
value
.
Len
())
}
for
i
:=
0
;
i
<
len
(
method
.
Outputs
);
i
++
{
marshalledValue
,
err
:=
toGoType
(
i
,
method
.
Outputs
[
i
],
output
)
if
err
!=
nil
{
return
err
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
if
err
:=
set
(
value
.
Index
(
i
)
.
Elem
(),
reflectValue
,
method
.
Outputs
[
i
]);
err
!=
nil
{
return
err
}
}
return
nil
}
// create a new slice and start appending the unmarshalled
// values to the new interface slice.
z
:=
reflect
.
MakeSlice
(
typ
,
0
,
len
(
method
.
Outputs
))
for
i
:=
0
;
i
<
len
(
method
.
Outputs
);
i
++
{
marshalledValue
,
err
:=
toGoType
(
i
,
method
.
Outputs
[
i
],
output
)
if
err
!=
nil
{
return
err
}
z
=
reflect
.
Append
(
z
,
reflect
.
ValueOf
(
marshalledValue
))
}
value
.
Set
(
z
)
default
:
return
fmt
.
Errorf
(
"abi: cannot unmarshal tuple in to %v"
,
typ
)
}
// 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
{
unpack
=
method
}
else
if
event
,
ok
:=
abi
.
Events
[
name
];
ok
{
unpack
=
event
}
else
{
marshalledValue
,
err
:=
toGoType
(
0
,
method
.
Outputs
[
0
],
output
)
if
err
!=
nil
{
return
err
}
if
err
:=
set
(
value
,
reflect
.
ValueOf
(
marshalledValue
),
method
.
Outputs
[
0
]);
err
!=
nil
{
return
err
}
return
fmt
.
Errorf
(
"abi: could not locate named method or event."
)
}
return
nil
// requires a struct to unpack into for a tuple return...
if
unpack
.
isTupleReturn
()
{
return
unpack
.
tupleUnpack
(
v
,
output
)
}
return
unpack
.
singleUnpack
(
v
,
output
)
}
func
(
abi
*
ABI
)
UnmarshalJSON
(
data
[]
byte
)
error
{
...
...
accounts/abi/abi_test.go
View file @
dec8bba9
...
...
@@ -29,25 +29,6 @@ import (
"github.com/ethereum/go-ethereum/crypto"
)
// formatSilceOutput add padding to the value and adds a size
func
formatSliceOutput
(
v
...
[]
byte
)
[]
byte
{
off
:=
common
.
LeftPadBytes
(
big
.
NewInt
(
int64
(
len
(
v
)))
.
Bytes
(),
32
)
output
:=
append
(
off
,
make
([]
byte
,
0
,
len
(
v
)
*
32
)
...
)
for
_
,
value
:=
range
v
{
output
=
append
(
output
,
common
.
LeftPadBytes
(
value
,
32
)
...
)
}
return
output
}
// quick helper padding
func
pad
(
input
[]
byte
,
size
int
,
left
bool
)
[]
byte
{
if
left
{
return
common
.
LeftPadBytes
(
input
,
size
)
}
return
common
.
RightPadBytes
(
input
,
size
)
}
const
jsondata
=
`
[
{ "type" : "function", "name" : "balance", "constant" : true },
...
...
@@ -191,7 +172,7 @@ func TestMethodSignature(t *testing.T) {
t
.
Errorf
(
"expected ids to match %x != %x"
,
m
.
Id
(),
idexp
)
}
uintt
,
_
:=
NewType
(
"uint"
)
uintt
,
_
:=
NewType
(
"uint
256
"
)
m
=
Method
{
"foo"
,
false
,
[]
Argument
{{
"bar"
,
uintt
,
false
}},
nil
}
exp
=
"foo(uint256)"
if
m
.
Sig
()
!=
exp
{
...
...
accounts/abi/bind/bind_test.go
View file @
dec8bba9
...
...
@@ -472,7 +472,7 @@ func TestBindings(t *testing.T) {
t
.
Fatalf
(
"failed to create temporary workspace: %v"
,
err
)
}
defer
os
.
RemoveAll
(
ws
)
pkg
:=
filepath
.
Join
(
ws
,
"bindtest"
)
if
err
=
os
.
MkdirAll
(
pkg
,
0700
);
err
!=
nil
{
t
.
Fatalf
(
"failed to create package: %v"
,
err
)
...
...
accounts/abi/error.go
View file @
dec8bba9
...
...
@@ -39,22 +39,23 @@ func formatSliceString(kind reflect.Kind, sliceSize int) string {
// type in t.
func
sliceTypeCheck
(
t
Type
,
val
reflect
.
Value
)
error
{
if
val
.
Kind
()
!=
reflect
.
Slice
&&
val
.
Kind
()
!=
reflect
.
Array
{
return
typeErr
(
formatSliceString
(
t
.
Kind
,
t
.
S
liceS
ize
),
val
.
Type
())
return
typeErr
(
formatSliceString
(
t
.
Kind
,
t
.
Size
),
val
.
Type
())
}
if
t
.
IsArray
&&
val
.
Len
()
!=
t
.
SliceSize
{
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
SliceSize
),
formatSliceString
(
val
.
Type
()
.
Elem
()
.
Kind
(),
val
.
Len
()))
if
t
.
T
==
ArrayTy
&&
val
.
Len
()
!=
t
.
Size
{
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
Size
),
formatSliceString
(
val
.
Type
()
.
Elem
()
.
Kind
(),
val
.
Len
()))
}
if
t
.
Elem
.
IsSlice
{
if
t
.
Elem
.
T
==
SliceTy
{
if
val
.
Len
()
>
0
{
return
sliceTypeCheck
(
*
t
.
Elem
,
val
.
Index
(
0
))
}
}
else
if
t
.
Elem
.
IsArra
y
{
}
else
if
t
.
Elem
.
T
==
ArrayT
y
{
return
sliceTypeCheck
(
*
t
.
Elem
,
val
.
Index
(
0
))
}
if
elemKind
:=
val
.
Type
()
.
Elem
()
.
Kind
();
elemKind
!=
t
.
Elem
.
Kind
{
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
S
liceS
ize
),
val
.
Type
())
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
Size
),
val
.
Type
())
}
return
nil
}
...
...
@@ -62,20 +63,19 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
// typeCheck checks that the given reflection value can be assigned to the reflection
// type in t.
func
typeCheck
(
t
Type
,
value
reflect
.
Value
)
error
{
if
t
.
IsSlice
||
t
.
IsArra
y
{
if
t
.
T
==
SliceTy
||
t
.
T
==
ArrayT
y
{
return
sliceTypeCheck
(
t
,
value
)
}
// Check base type validity. Element types will be checked later on.
if
t
.
Kind
!=
value
.
Kind
()
{
return
typeErr
(
t
.
Kind
,
value
.
Kind
())
}
else
if
t
.
T
==
FixedBytesTy
&&
t
.
Size
!=
value
.
Len
()
{
return
typeErr
(
t
.
Type
,
value
.
Type
())
}
else
{
return
nil
}
return
nil
}
// varErr returns a formatted error.
func
varErr
(
expected
,
got
reflect
.
Kind
)
error
{
return
typeErr
(
expected
,
got
)
}
// typeErr returns a formatted type casting error.
...
...
accounts/abi/event.go
View file @
dec8bba9
...
...
@@ -18,6 +18,7 @@ package abi
import
(
"fmt"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -44,3 +45,93 @@ func (e Event) Id() common.Hash {
}
return
common
.
BytesToHash
(
crypto
.
Keccak256
([]
byte
(
fmt
.
Sprintf
(
"%v(%v)"
,
e
.
Name
,
strings
.
Join
(
types
,
","
)))))
}
// unpacks an event return tuple into a struct of corresponding go types
//
// Unpacking can be done into a struct or a slice/array.
func
(
e
Event
)
tupleUnpack
(
v
interface
{},
output
[]
byte
)
error
{
// make sure the passed value is a pointer
valueOf
:=
reflect
.
ValueOf
(
v
)
if
reflect
.
Ptr
!=
valueOf
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
}
var
(
value
=
valueOf
.
Elem
()
typ
=
value
.
Type
()
)
if
value
.
Kind
()
!=
reflect
.
Struct
{
return
fmt
.
Errorf
(
"abi: cannot unmarshal tuple in to %v"
,
typ
)
}
j
:=
0
for
i
:=
0
;
i
<
len
(
e
.
Inputs
);
i
++
{
input
:=
e
.
Inputs
[
i
]
if
input
.
Indexed
{
// can't read, continue
continue
}
else
if
input
.
Type
.
T
==
ArrayTy
{
// need to move this up because they read sequentially
j
+=
input
.
Type
.
Size
}
marshalledValue
,
err
:=
toGoType
((
i
+
j
)
*
32
,
input
.
Type
,
output
)
if
err
!=
nil
{
return
err
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
switch
value
.
Kind
()
{
case
reflect
.
Struct
:
for
j
:=
0
;
j
<
typ
.
NumField
();
j
++
{
field
:=
typ
.
Field
(
j
)
// TODO read tags: `abi:"fieldName"`
if
field
.
Name
==
strings
.
ToUpper
(
e
.
Inputs
[
i
]
.
Name
[
:
1
])
+
e
.
Inputs
[
i
]
.
Name
[
1
:
]
{
if
err
:=
set
(
value
.
Field
(
j
),
reflectValue
,
e
.
Inputs
[
i
]);
err
!=
nil
{
return
err
}
}
}
case
reflect
.
Slice
,
reflect
.
Array
:
if
value
.
Len
()
<
i
{
return
fmt
.
Errorf
(
"abi: insufficient number of arguments for unpack, want %d, got %d"
,
len
(
e
.
Inputs
),
value
.
Len
())
}
v
:=
value
.
Index
(
i
)
if
v
.
Kind
()
!=
reflect
.
Ptr
&&
v
.
Kind
()
!=
reflect
.
Interface
{
return
fmt
.
Errorf
(
"abi: cannot unmarshal %v in to %v"
,
v
.
Type
(),
reflectValue
.
Type
())
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
if
err
:=
set
(
v
.
Elem
(),
reflectValue
,
e
.
Inputs
[
i
]);
err
!=
nil
{
return
err
}
default
:
return
fmt
.
Errorf
(
"abi: cannot unmarshal tuple in to %v"
,
typ
)
}
}
return
nil
}
func
(
e
Event
)
isTupleReturn
()
bool
{
return
len
(
e
.
Inputs
)
>
1
}
func
(
e
Event
)
singleUnpack
(
v
interface
{},
output
[]
byte
)
error
{
// make sure the passed value is a pointer
valueOf
:=
reflect
.
ValueOf
(
v
)
if
reflect
.
Ptr
!=
valueOf
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
}
if
e
.
Inputs
[
0
]
.
Indexed
{
return
fmt
.
Errorf
(
"abi: attempting to unpack indexed variable into element."
)
}
value
:=
valueOf
.
Elem
()
marshalledValue
,
err
:=
toGoType
(
0
,
e
.
Inputs
[
0
]
.
Type
,
output
)
if
err
!=
nil
{
return
err
}
if
err
:=
set
(
value
,
reflect
.
ValueOf
(
marshalledValue
),
e
.
Inputs
[
0
]);
err
!=
nil
{
return
err
}
return
nil
}
accounts/abi/event_test.go
View file @
dec8bba9
...
...
@@ -31,7 +31,7 @@ func TestEventId(t *testing.T) {
}{
{
definition
:
`[
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint" }] },
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint
256
" }] },
{ "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }
]`
,
expectations
:
map
[
string
]
common
.
Hash
{
...
...
accounts/abi/method.go
View file @
dec8bba9
...
...
@@ -77,6 +77,85 @@ func (method Method) pack(args ...interface{}) ([]byte, error) {
return
ret
,
nil
}
// unpacks a method return tuple into a struct of corresponding go types
//
// Unpacking can be done into a struct or a slice/array.
func
(
method
Method
)
tupleUnpack
(
v
interface
{},
output
[]
byte
)
error
{
// make sure the passed value is a pointer
valueOf
:=
reflect
.
ValueOf
(
v
)
if
reflect
.
Ptr
!=
valueOf
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
}
var
(
value
=
valueOf
.
Elem
()
typ
=
value
.
Type
()
)
j
:=
0
for
i
:=
0
;
i
<
len
(
method
.
Outputs
);
i
++
{
toUnpack
:=
method
.
Outputs
[
i
]
if
toUnpack
.
Type
.
T
==
ArrayTy
{
// need to move this up because they read sequentially
j
+=
toUnpack
.
Type
.
Size
}
marshalledValue
,
err
:=
toGoType
((
i
+
j
)
*
32
,
toUnpack
.
Type
,
output
)
if
err
!=
nil
{
return
err
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
switch
value
.
Kind
()
{
case
reflect
.
Struct
:
for
j
:=
0
;
j
<
typ
.
NumField
();
j
++
{
field
:=
typ
.
Field
(
j
)
// TODO read tags: `abi:"fieldName"`
if
field
.
Name
==
strings
.
ToUpper
(
method
.
Outputs
[
i
]
.
Name
[
:
1
])
+
method
.
Outputs
[
i
]
.
Name
[
1
:
]
{
if
err
:=
set
(
value
.
Field
(
j
),
reflectValue
,
method
.
Outputs
[
i
]);
err
!=
nil
{
return
err
}
}
}
case
reflect
.
Slice
,
reflect
.
Array
:
if
value
.
Len
()
<
i
{
return
fmt
.
Errorf
(
"abi: insufficient number of arguments for unpack, want %d, got %d"
,
len
(
method
.
Outputs
),
value
.
Len
())
}
v
:=
value
.
Index
(
i
)
if
v
.
Kind
()
!=
reflect
.
Ptr
&&
v
.
Kind
()
!=
reflect
.
Interface
{
return
fmt
.
Errorf
(
"abi: cannot unmarshal %v in to %v"
,
v
.
Type
(),
reflectValue
.
Type
())
}
reflectValue
:=
reflect
.
ValueOf
(
marshalledValue
)
if
err
:=
set
(
v
.
Elem
(),
reflectValue
,
method
.
Outputs
[
i
]);
err
!=
nil
{
return
err
}
default
:
return
fmt
.
Errorf
(
"abi: cannot unmarshal tuple in to %v"
,
typ
)
}
}
return
nil
}
func
(
method
Method
)
isTupleReturn
()
bool
{
return
len
(
method
.
Outputs
)
>
1
}
func
(
method
Method
)
singleUnpack
(
v
interface
{},
output
[]
byte
)
error
{
// make sure the passed value is a pointer
valueOf
:=
reflect
.
ValueOf
(
v
)
if
reflect
.
Ptr
!=
valueOf
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
}
value
:=
valueOf
.
Elem
()
marshalledValue
,
err
:=
toGoType
(
0
,
method
.
Outputs
[
0
]
.
Type
,
output
)
if
err
!=
nil
{
return
err
}
if
err
:=
set
(
value
,
reflect
.
ValueOf
(
marshalledValue
),
method
.
Outputs
[
0
]);
err
!=
nil
{
return
err
}
return
nil
}
// Sig returns the methods string signature according to the ABI spec.
//
// Example
...
...
accounts/abi/numbers.go
View file @
dec8bba9
...
...
@@ -25,36 +25,23 @@ import (
)
var
(
big_t
=
reflect
.
TypeOf
(
big
.
Int
{})
ubig_t
=
reflect
.
TypeOf
(
big
.
Int
{})
byte_t
=
reflect
.
TypeOf
(
byte
(
0
))
byte_ts
=
reflect
.
TypeOf
([]
byte
(
nil
))
uint_t
=
reflect
.
TypeOf
(
uint
(
0
))
uint8_t
=
reflect
.
TypeOf
(
uint8
(
0
))
uint16_t
=
reflect
.
TypeOf
(
uint16
(
0
))
uint32_t
=
reflect
.
TypeOf
(
uint32
(
0
))
uint64_t
=
reflect
.
TypeOf
(
uint64
(
0
))
int_t
=
reflect
.
TypeOf
(
int
(
0
))
int8_t
=
reflect
.
TypeOf
(
int8
(
0
))
int16_t
=
reflect
.
TypeOf
(
int16
(
0
))
int32_t
=
reflect
.
TypeOf
(
int32
(
0
))
int64_t
=
reflect
.
TypeOf
(
int64
(
0
))
hash_t
=
reflect
.
TypeOf
(
common
.
Hash
{})
address_t
=
reflect
.
TypeOf
(
common
.
Address
{})
uint_ts
=
reflect
.
TypeOf
([]
uint
(
nil
))
uint8_ts
=
reflect
.
TypeOf
([]
uint8
(
nil
))
uint16_ts
=
reflect
.
TypeOf
([]
uint16
(
nil
))
uint32_ts
=
reflect
.
TypeOf
([]
uint32
(
nil
))
uint64_ts
=
reflect
.
TypeOf
([]
uint64
(
nil
))
ubig_ts
=
reflect
.
TypeOf
([]
*
big
.
Int
(
nil
))
int_ts
=
reflect
.
TypeOf
([]
int
(
nil
))
int8_ts
=
reflect
.
TypeOf
([]
int8
(
nil
))
int16_ts
=
reflect
.
TypeOf
([]
int16
(
nil
))
int32_ts
=
reflect
.
TypeOf
([]
int32
(
nil
))
int64_ts
=
reflect
.
TypeOf
([]
int64
(
nil
))
big_ts
=
reflect
.
TypeOf
([]
*
big
.
Int
(
nil
))
big_t
=
reflect
.
TypeOf
(
&
big
.
Int
{})
derefbig_t
=
reflect
.
TypeOf
(
big
.
Int
{})
uint8_t
=
reflect
.
TypeOf
(
uint8
(
0
))
uint16_t
=
reflect
.
TypeOf
(
uint16
(
0
))
uint32_t
=
reflect
.
TypeOf
(
uint32
(
0
))
uint64_t
=
reflect
.
TypeOf
(
uint64
(
0
))
int_t
=
reflect
.
TypeOf
(
int
(
0
))
int8_t
=
reflect
.
TypeOf
(
int8
(
0
))
int16_t
=
reflect
.
TypeOf
(
int16
(
0
))
int32_t
=
reflect
.
TypeOf
(
int32
(
0
))
int64_t
=
reflect
.
TypeOf
(
int64
(
0
))
address_t
=
reflect
.
TypeOf
(
common
.
Address
{})
int_ts
=
reflect
.
TypeOf
([]
int
(
nil
))
int8_ts
=
reflect
.
TypeOf
([]
int8
(
nil
))
int16_ts
=
reflect
.
TypeOf
([]
int16
(
nil
))
int32_ts
=
reflect
.
TypeOf
([]
int32
(
nil
))
int64_ts
=
reflect
.
TypeOf
([]
int64
(
nil
))
)
// U256 converts a big Int into a 256bit EVM number.
...
...
accounts/abi/pack.go
View file @
dec8bba9
...
...
@@ -61,8 +61,9 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
reflectValue
=
mustArrayToByteSlice
(
reflectValue
)
}
return
common
.
RightPadBytes
(
reflectValue
.
Bytes
(),
32
)
default
:
panic
(
"abi: fatal error"
)
}
panic
(
"abi: fatal error"
)
}
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
...
...
@@ -74,6 +75,8 @@ func packNum(value reflect.Value) []byte {
return
U256
(
big
.
NewInt
(
value
.
Int
()))
case
reflect
.
Ptr
:
return
U256
(
value
.
Interface
()
.
(
*
big
.
Int
))
default
:
panic
(
"abi: fatal error"
)
}
return
nil
}
accounts/abi/pack_test.go
View file @
dec8bba9
...
...
@@ -322,12 +322,12 @@ func TestPack(t *testing.T) {
}
{
typ
,
err
:=
NewType
(
test
.
typ
)
if
err
!=
nil
{
t
.
Fatal
(
"unexpected parse error:"
,
err
)
t
.
Fatal
f
(
"%v failed. Unexpected parse error: %v"
,
i
,
err
)
}
output
,
err
:=
typ
.
pack
(
reflect
.
ValueOf
(
test
.
input
))
if
err
!=
nil
{
t
.
Fatal
(
"unexpected pack error:"
,
err
)
t
.
Fatal
f
(
"%v failed. Unexpected pack error: %v"
,
i
,
err
)
}
if
!
bytes
.
Equal
(
output
,
test
.
output
)
{
...
...
@@ -435,7 +435,4 @@ func TestPackNumber(t *testing.T) {
t
.
Errorf
(
"test %d: pack mismatch: have %x, want %x"
,
i
,
packed
,
tt
.
packed
)
}
}
if
packed
:=
packNum
(
reflect
.
ValueOf
(
"string"
));
packed
!=
nil
{
t
.
Errorf
(
"expected 'string' to pack to nil. got %x instead"
,
packed
)
}
}
accounts/abi/reflect.go
View file @
dec8bba9
...
...
@@ -24,7 +24,7 @@ import (
// indirect recursively dereferences the value until it either gets the value
// or finds a big.Int
func
indirect
(
v
reflect
.
Value
)
reflect
.
Value
{
if
v
.
Kind
()
==
reflect
.
Ptr
&&
v
.
Elem
()
.
Type
()
!=
big_t
{
if
v
.
Kind
()
==
reflect
.
Ptr
&&
v
.
Elem
()
.
Type
()
!=
deref
big_t
{
return
indirect
(
v
.
Elem
())
}
return
v
...
...
@@ -73,15 +73,9 @@ func mustArrayToByteSlice(value reflect.Value) reflect.Value {
func
set
(
dst
,
src
reflect
.
Value
,
output
Argument
)
error
{
dstType
:=
dst
.
Type
()
srcType
:=
src
.
Type
()
switch
{
case
dstType
.
AssignableTo
(
src
.
Type
()
)
:
case
dstType
.
AssignableTo
(
src
Type
)
:
dst
.
Set
(
src
)
case
dstType
.
Kind
()
==
reflect
.
Array
&&
srcType
.
Kind
()
==
reflect
.
Slice
:
if
dst
.
Len
()
<
output
.
Type
.
SliceSize
{
return
fmt
.
Errorf
(
"abi: cannot unmarshal src (len=%d) in to dst (len=%d)"
,
output
.
Type
.
SliceSize
,
dst
.
Len
())
}
reflect
.
Copy
(
dst
,
src
)
case
dstType
.
Kind
()
==
reflect
.
Interface
:
dst
.
Set
(
src
)
case
dstType
.
Kind
()
==
reflect
.
Ptr
:
...
...
accounts/abi/type.go
View file @
dec8bba9
...
...
@@ -21,6 +21,7 @@ import (
"reflect"
"regexp"
"strconv"
"strings"
)
const
(
...
...
@@ -29,6 +30,7 @@ const (
BoolTy
StringTy
SliceTy
ArrayTy
AddressTy
FixedBytesTy
BytesTy
...
...
@@ -39,9 +41,6 @@ const (
// Type is the reflection of the supported argument type
type
Type
struct
{
IsSlice
,
IsArray
bool
SliceSize
int
Elem
*
Type
Kind
reflect
.
Kind
...
...
@@ -53,118 +52,116 @@ type Type struct {
}
var
(
// fullTypeRegex parses the abi types
//
// Types can be in the format of:
//
// Input = Type [ "[" [ Number ] "]" ] Name .
// Type = [ "u" ] "int" [ Number ] [ x ] [ Number ].
//
// Examples:
//
// string int uint fixed
// string32 int8 uint8 uint[]
// address int256 uint256 fixed128x128[2]
fullTypeRegex
=
regexp
.
MustCompile
(
`([a-zA-Z0-9]+)(\[([0-9]*)\])?`
)
// typeRegex parses the abi sub types
typeRegex
=
regexp
.
MustCompile
(
"([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?"
)
)
// NewType creates a new reflection type of abi type given in t.
func
NewType
(
t
string
)
(
typ
Type
,
err
error
)
{
res
:=
fullTypeRegex
.
FindAllStringSubmatch
(
t
,
-
1
)[
0
]
// check if type is slice and parse type.
switch
{
case
res
[
3
]
!=
""
:
// err is ignored. Already checked for number through the regexp
typ
.
SliceSize
,
_
=
strconv
.
Atoi
(
res
[
3
])
typ
.
IsArray
=
true
case
res
[
2
]
!=
""
:
typ
.
IsSlice
,
typ
.
SliceSize
=
true
,
-
1
case
res
[
0
]
==
""
:
return
Type
{},
fmt
.
Errorf
(
"abi: type parse error: %s"
,
t
)
// check that array brackets are equal if they exist
if
strings
.
Count
(
t
,
"["
)
!=
strings
.
Count
(
t
,
"]"
)
{
return
Type
{},
fmt
.
Errorf
(
"invalid arg type in abi"
)
}
if
typ
.
IsArray
||
typ
.
IsSlice
{
sliceType
,
err
:=
NewType
(
res
[
1
])
typ
.
stringKind
=
t
// if there are brackets, get ready to go into slice/array mode and
// recursively create the type
if
strings
.
Count
(
t
,
"["
)
!=
0
{
i
:=
strings
.
LastIndex
(
t
,
"["
)
// recursively embed the type
embeddedType
,
err
:=
NewType
(
t
[
:
i
])
if
err
!=
nil
{
return
Type
{},
err
}
typ
.
Elem
=
&
sliceType
typ
.
stringKind
=
sliceType
.
stringKind
+
t
[
len
(
res
[
1
])
:
]
// Although we know that this is an array, we cannot return
// as we don't know the type of the element, however, if it
// is still an array, then don't determine the type.
if
typ
.
Elem
.
IsArray
||
typ
.
Elem
.
IsSlice
{
return
typ
,
nil
}
}
// parse the type and size of the abi-type.
parsedType
:=
typeRegex
.
FindAllStringSubmatch
(
res
[
1
],
-
1
)[
0
]
// varSize is the size of the variable
var
varSize
int
if
len
(
parsedType
[
3
])
>
0
{
var
err
error
varSize
,
err
=
strconv
.
Atoi
(
parsedType
[
2
])
if
err
!=
nil
{
return
Type
{},
fmt
.
Errorf
(
"abi: error parsing variable size: %v"
,
err
)
// grab the last cell and create a type from there
sliced
:=
t
[
i
:
]
// grab the slice size with regexp
re
:=
regexp
.
MustCompile
(
"[0-9]+"
)
intz
:=
re
.
FindAllString
(
sliced
,
-
1
)
if
len
(
intz
)
==
0
{
// is a slice
typ
.
T
=
SliceTy
typ
.
Kind
=
reflect
.
Slice
typ
.
Elem
=
&
embeddedType
typ
.
Type
=
reflect
.
SliceOf
(
embeddedType
.
Type
)
}
else
if
len
(
intz
)
==
1
{
// is a array
typ
.
T
=
ArrayTy
typ
.
Kind
=
reflect
.
Array
typ
.
Elem
=
&
embeddedType
typ
.
Size
,
err
=
strconv
.
Atoi
(
intz
[
0
])
if
err
!=
nil
{
return
Type
{},
fmt
.
Errorf
(
"abi: error parsing variable size: %v"
,
err
)
}
typ
.
Type
=
reflect
.
ArrayOf
(
typ
.
Size
,
embeddedType
.
Type
)
}
else
{
return
Type
{},
fmt
.
Errorf
(
"invalid formatting of array type"
)
}
}
// varType is the parsed abi type
varType
:=
parsedType
[
1
]
// substitute canonical integer
if
varSize
==
0
&&
(
varType
==
"int"
||
varType
==
"uint"
)
{
varSize
=
256
t
+=
"256"
}
// only set stringKind if not array or slice, as for those,
// the correct string type has been set
if
!
(
typ
.
IsArray
||
typ
.
IsSlice
)
{
typ
.
stringKind
=
t
}
switch
varType
{
case
"int"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
false
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
IntTy
case
"uint"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
true
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
UintTy
case
"bool"
:
typ
.
Kind
=
reflect
.
Bool
typ
.
T
=
BoolTy
case
"address"
:
typ
.
Kind
=
reflect
.
Array
typ
.
Type
=
address_t
typ
.
Size
=
20
typ
.
T
=
AddressTy
case
"string"
:
typ
.
Kind
=
reflect
.
String
typ
.
Size
=
-
1
typ
.
T
=
StringTy
case
"bytes"
:
sliceType
,
_
:=
NewType
(
"uint8"
)
typ
.
Elem
=
&
sliceType
if
varSize
==
0
{
typ
.
IsSlice
=
true
typ
.
T
=
BytesTy
typ
.
SliceSize
=
-
1
return
typ
,
err
}
else
{
// parse the type and size of the abi-type.
parsedType
:=
typeRegex
.
FindAllStringSubmatch
(
t
,
-
1
)[
0
]
// varSize is the size of the variable
var
varSize
int
if
len
(
parsedType
[
3
])
>
0
{
var
err
error
varSize
,
err
=
strconv
.
Atoi
(
parsedType
[
2
])
if
err
!=
nil
{
return
Type
{},
fmt
.
Errorf
(
"abi: error parsing variable size: %v"
,
err
)
}
}
else
{
typ
.
IsArray
=
true
typ
.
T
=
FixedBytesTy
typ
.
SliceSize
=
varSize
if
parsedType
[
0
]
==
"uint"
||
parsedType
[
0
]
==
"int"
{
// this should fail because it means that there's something wrong with
// the abi type (the compiler should always format it to the size...always)
return
Type
{},
fmt
.
Errorf
(
"unsupported arg type: %s"
,
t
)
}
}
// varType is the parsed abi type
varType
:=
parsedType
[
1
]
switch
varType
{
case
"int"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
false
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
IntTy
case
"uint"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
true
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
UintTy
case
"bool"
:
typ
.
Kind
=
reflect
.
Bool
typ
.
T
=
BoolTy
typ
.
Type
=
reflect
.
TypeOf
(
bool
(
false
))
case
"address"
:
typ
.
Kind
=
reflect
.
Array
typ
.
Type
=
address_t
typ
.
Size
=
20
typ
.
T
=
AddressTy
case
"string"
:
typ
.
Kind
=
reflect
.
String
typ
.
Type
=
reflect
.
TypeOf
(
""
)
typ
.
T
=
StringTy
case
"bytes"
:
if
varSize
==
0
{
typ
.
T
=
BytesTy
typ
.
Kind
=
reflect
.
Slice
typ
.
Type
=
reflect
.
SliceOf
(
reflect
.
TypeOf
(
byte
(
0
)))
}
else
{
typ
.
T
=
FixedBytesTy
typ
.
Kind
=
reflect
.
Array
typ
.
Size
=
varSize
typ
.
Type
=
reflect
.
ArrayOf
(
varSize
,
reflect
.
TypeOf
(
byte
(
0
)))
}
case
"function"
:
typ
.
Kind
=
reflect
.
Array
typ
.
T
=
FunctionTy
typ
.
Size
=
24
typ
.
Type
=
reflect
.
ArrayOf
(
24
,
reflect
.
TypeOf
(
byte
(
0
)))
default
:
return
Type
{},
fmt
.
Errorf
(
"unsupported arg type: %s"
,
t
)
}
case
"function"
:
sliceType
,
_
:=
NewType
(
"uint8"
)
typ
.
Elem
=
&
sliceType
typ
.
IsArray
=
true
typ
.
T
=
FunctionTy
typ
.
SliceSize
=
24
default
:
return
Type
{},
fmt
.
Errorf
(
"unsupported arg type: %s"
,
t
)
}
return
...
...
@@ -183,7 +180,7 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
return
nil
,
err
}
if
(
t
.
IsSlice
||
t
.
IsArray
)
&&
t
.
T
!=
BytesTy
&&
t
.
T
!=
FixedBytesTy
&&
t
.
T
!=
Function
Ty
{
if
t
.
T
==
SliceTy
||
t
.
T
==
Array
Ty
{
var
packed
[]
byte
for
i
:=
0
;
i
<
v
.
Len
();
i
++
{
...
...
@@ -193,18 +190,17 @@ func (t Type) pack(v reflect.Value) ([]byte, error) {
}
packed
=
append
(
packed
,
val
...
)
}
if
t
.
IsSlice
{
if
t
.
T
==
SliceTy
{
return
packBytesSlice
(
packed
,
v
.
Len
()),
nil
}
else
if
t
.
IsArra
y
{
}
else
if
t
.
T
==
ArrayT
y
{
return
packed
,
nil
}
}
return
packElement
(
t
,
v
),
nil
}
// requireLengthPrefix returns whether the type requires any sort of length
// prefixing.
func
(
t
Type
)
requiresLengthPrefix
()
bool
{
return
t
.
T
!=
FixedBytesTy
&&
(
t
.
T
==
StringTy
||
t
.
T
==
BytesTy
||
t
.
IsSlice
)
return
t
.
T
==
StringTy
||
t
.
T
==
BytesTy
||
t
.
T
==
SliceTy
}
accounts/abi/type_test.go
View file @
dec8bba9
This diff is collapsed.
Click to expand it.
accounts/abi/unpack.go
View file @
dec8bba9
This diff is collapsed.
Click to expand it.
accounts/abi/unpack_test.go
View file @
dec8bba9
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment