accounts/abi: ABI fixes & added types
Changed field `input` to new `inputs`. Addad Hash and Address as input types. Added bytes[N] and N validation
This commit is contained in:
parent
6b5a42a15c
commit
1f72952f04
@ -36,7 +36,7 @@ import (
|
|||||||
type Method struct {
|
type Method struct {
|
||||||
Name string
|
Name string
|
||||||
Const bool
|
Const bool
|
||||||
Input []Argument
|
Inputs []Argument
|
||||||
Return Type // not yet implemented
|
Return Type // not yet implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,9 +49,9 @@ type Method struct {
|
|||||||
// Please note that "int" is substitute for its canonical representation "int256"
|
// Please note that "int" is substitute for its canonical representation "int256"
|
||||||
func (m Method) String() (out string) {
|
func (m Method) String() (out string) {
|
||||||
out += m.Name
|
out += m.Name
|
||||||
types := make([]string, len(m.Input))
|
types := make([]string, len(m.Inputs))
|
||||||
i := 0
|
i := 0
|
||||||
for _, input := range m.Input {
|
for _, input := range m.Inputs {
|
||||||
types[i] = input.Type.String()
|
types[i] = input.Type.String()
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ func (abi ABI) pack(name string, args ...interface{}) ([]byte, error) {
|
|||||||
|
|
||||||
var ret []byte
|
var ret []byte
|
||||||
for i, a := range args {
|
for i, a := range args {
|
||||||
input := method.Input[i]
|
input := method.Inputs[i]
|
||||||
|
|
||||||
packed, err := input.Type.pack(a)
|
packed, err := input.Type.pack(a)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -129,8 +129,8 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start with argument count match
|
// start with argument count match
|
||||||
if len(args) != len(method.Input) {
|
if len(args) != len(method.Inputs) {
|
||||||
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Input))
|
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(method.Inputs))
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments, err := abi.pack(name, args...)
|
arguments, err := abi.pack(name, args...)
|
||||||
|
@ -18,35 +18,38 @@ package abi
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const jsondata = `
|
const jsondata = `
|
||||||
[
|
[
|
||||||
{ "name" : "balance", "const" : true },
|
{ "name" : "balance", "const" : true },
|
||||||
{ "name" : "send", "const" : false, "input" : [ { "name" : "amount", "type" : "uint256" } ] }
|
{ "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }
|
||||||
]`
|
]`
|
||||||
|
|
||||||
const jsondata2 = `
|
const jsondata2 = `
|
||||||
[
|
[
|
||||||
{ "name" : "balance", "const" : true },
|
{ "name" : "balance", "const" : true },
|
||||||
{ "name" : "send", "const" : false, "input" : [ { "name" : "amount", "type" : "uint256" } ] },
|
{ "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] },
|
||||||
{ "name" : "test", "const" : false, "input" : [ { "name" : "number", "type" : "uint32" } ] },
|
{ "name" : "test", "const" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] },
|
||||||
{ "name" : "string", "const" : false, "input" : [ { "name" : "input", "type" : "string" } ] },
|
{ "name" : "string", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] },
|
||||||
{ "name" : "bool", "const" : false, "input" : [ { "name" : "input", "type" : "bool" } ] },
|
{ "name" : "bool", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] },
|
||||||
{ "name" : "address", "const" : false, "input" : [ { "name" : "input", "type" : "address" } ] },
|
{ "name" : "address", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] },
|
||||||
{ "name" : "string32", "const" : false, "input" : [ { "name" : "input", "type" : "string32" } ] },
|
{ "name" : "string32", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "string32" } ] },
|
||||||
{ "name" : "uint64[2]", "const" : false, "input" : [ { "name" : "input", "type" : "uint64[2]" } ] },
|
{ "name" : "uint64[2]", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] },
|
||||||
{ "name" : "uint64[]", "const" : false, "input" : [ { "name" : "input", "type" : "uint64[]" } ] },
|
{ "name" : "uint64[]", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] },
|
||||||
{ "name" : "foo", "const" : false, "input" : [ { "name" : "input", "type" : "uint32" } ] },
|
{ "name" : "foo", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] },
|
||||||
{ "name" : "bar", "const" : false, "input" : [ { "name" : "input", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
|
{ "name" : "bar", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
|
||||||
{ "name" : "slice", "const" : false, "input" : [ { "name" : "input", "type" : "uint32[2]" } ] },
|
{ "name" : "slice", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] },
|
||||||
{ "name" : "slice256", "const" : false, "input" : [ { "name" : "input", "type" : "uint256[2]" } ] }
|
{ "name" : "slice256", "const" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] }
|
||||||
]`
|
]`
|
||||||
|
|
||||||
func TestType(t *testing.T) {
|
func TestType(t *testing.T) {
|
||||||
@ -344,3 +347,49 @@ func TestPackSliceBig(t *testing.T) {
|
|||||||
t.Errorf("expected %x got %x", sig, packed)
|
t.Errorf("expected %x got %x", sig, packed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleJSON() {
|
||||||
|
const definition = `[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]`
|
||||||
|
|
||||||
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
out, err := abi.Pack("isBar", common.HexToAddress("01"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%x\n", out)
|
||||||
|
// Output:
|
||||||
|
// 1f2c40920000000000000000000000000000000000000000000000000000000000000001
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBytes(t *testing.T) {
|
||||||
|
const definition = `[
|
||||||
|
{ "name" : "balance", "const" : true, "inputs" : [ { "name" : "address", "type" : "bytes20" } ] },
|
||||||
|
{ "name" : "send", "const" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }
|
||||||
|
]`
|
||||||
|
|
||||||
|
abi, err := JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ok := make([]byte, 20)
|
||||||
|
_, err = abi.Pack("balance", ok)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
toosmall := make([]byte, 19)
|
||||||
|
_, err = abi.Pack("balance", toosmall)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
toobig := make([]byte, 21)
|
||||||
|
_, err = abi.Pack("balance", toobig)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@ type Type struct {
|
|||||||
stringKind string // holds the unparsed string for deriving signatures
|
stringKind string // holds the unparsed string for deriving signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
// New type returns a fully parsed Type given by the input string or an error if it can't be parsed.
|
// NewType returns a fully parsed Type given by the input string or an error if it can't be parsed.
|
||||||
//
|
//
|
||||||
// Strings can be in the format of:
|
// Strings can be in the format of:
|
||||||
//
|
//
|
||||||
@ -130,6 +130,10 @@ func NewType(t string) (typ Type, err error) {
|
|||||||
if vsize > 0 {
|
if vsize > 0 {
|
||||||
typ.Size = 32
|
typ.Size = 32
|
||||||
}
|
}
|
||||||
|
case "bytes":
|
||||||
|
typ.Kind = reflect.Slice
|
||||||
|
typ.Type = byte_ts
|
||||||
|
typ.Size = vsize
|
||||||
default:
|
default:
|
||||||
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
return Type{}, fmt.Errorf("unsupported arg type: %s", t)
|
||||||
}
|
}
|
||||||
@ -200,7 +204,13 @@ func (t Type) pack(v interface{}) ([]byte, error) {
|
|||||||
} else {
|
} else {
|
||||||
return common.LeftPadBytes(common.Big0.Bytes(), 32), nil
|
return common.LeftPadBytes(common.Big0.Bytes(), 32), nil
|
||||||
}
|
}
|
||||||
|
case reflect.Array:
|
||||||
|
if v, ok := value.Interface().(common.Address); ok {
|
||||||
|
return t.pack(v[:])
|
||||||
|
} else if v, ok := value.Interface().(common.Hash); ok {
|
||||||
|
return t.pack(v[:])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("unreached")
|
return nil, fmt.Errorf("ABI: bad input given %T", value.Kind())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user