forked from TrueCloudLab/neoneo-go
Merge pull request #1603 from nspcc-dev/compiler/types
compiler: enforce `Hash160` and `Hash256` size in literals
This commit is contained in:
commit
a3f91ba8c5
3 changed files with 77 additions and 21 deletions
|
@ -14,6 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||||
|
@ -746,12 +747,27 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.CompositeLit:
|
case *ast.CompositeLit:
|
||||||
switch typ := c.typeOf(n).Underlying().(type) {
|
t := c.typeOf(n)
|
||||||
|
switch typ := t.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
c.convertStruct(n, false)
|
c.convertStruct(n, false)
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
c.convertMap(n)
|
c.convertMap(n)
|
||||||
default:
|
default:
|
||||||
|
if tn, ok := t.(*types.Named); ok && isInteropPath(tn.String()) {
|
||||||
|
st, _ := scAndVMInteropTypeFromExpr(tn)
|
||||||
|
expectedLen := -1
|
||||||
|
switch st {
|
||||||
|
case smartcontract.Hash160Type:
|
||||||
|
expectedLen = 20
|
||||||
|
case smartcontract.Hash256Type:
|
||||||
|
expectedLen = 32
|
||||||
|
}
|
||||||
|
if expectedLen != -1 && expectedLen != len(n.Elts) {
|
||||||
|
c.prog.Err = fmt.Errorf("%s type must have size %d", tn.Obj().Name(), expectedLen)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
ln := len(n.Elts)
|
ln := len(n.Elts)
|
||||||
// ByteArrays needs a different approach than normal arrays.
|
// ByteArrays needs a different approach than normal arrays.
|
||||||
if isByteSlice(typ) {
|
if isByteSlice(typ) {
|
||||||
|
|
|
@ -228,6 +228,29 @@ func (c *codegen) scAndVMReturnTypeFromScope(scope *funcScope) (smartcontract.Pa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func scAndVMInteropTypeFromExpr(named *types.Named) (smartcontract.ParamType, stackitem.Type) {
|
||||||
|
name := named.Obj().Name()
|
||||||
|
pkg := named.Obj().Pkg().Name()
|
||||||
|
switch pkg {
|
||||||
|
case "blockchain", "contract":
|
||||||
|
return smartcontract.ArrayType, stackitem.ArrayT // Block, Transaction, Contract
|
||||||
|
case "interop":
|
||||||
|
if name != "Interface" {
|
||||||
|
switch name {
|
||||||
|
case "Hash160":
|
||||||
|
return smartcontract.Hash160Type, stackitem.ByteArrayT
|
||||||
|
case "Hash256":
|
||||||
|
return smartcontract.Hash256Type, stackitem.ByteArrayT
|
||||||
|
case "PublicKey":
|
||||||
|
return smartcontract.PublicKeyType, stackitem.ByteArrayT
|
||||||
|
case "Signature":
|
||||||
|
return smartcontract.SignatureType, stackitem.ByteArrayT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return smartcontract.InteropInterfaceType, stackitem.InteropT
|
||||||
|
}
|
||||||
|
|
||||||
func (c *codegen) scAndVMTypeFromExpr(typ ast.Expr) (smartcontract.ParamType, stackitem.Type) {
|
func (c *codegen) scAndVMTypeFromExpr(typ ast.Expr) (smartcontract.ParamType, stackitem.Type) {
|
||||||
t := c.typeOf(typ)
|
t := c.typeOf(typ)
|
||||||
if c.typeOf(typ) == nil {
|
if c.typeOf(typ) == nil {
|
||||||
|
@ -235,26 +258,7 @@ func (c *codegen) scAndVMTypeFromExpr(typ ast.Expr) (smartcontract.ParamType, st
|
||||||
}
|
}
|
||||||
if named, ok := t.(*types.Named); ok {
|
if named, ok := t.(*types.Named); ok {
|
||||||
if isInteropPath(named.String()) {
|
if isInteropPath(named.String()) {
|
||||||
name := named.Obj().Name()
|
return scAndVMInteropTypeFromExpr(named)
|
||||||
pkg := named.Obj().Pkg().Name()
|
|
||||||
switch pkg {
|
|
||||||
case "blockchain", "contract":
|
|
||||||
return smartcontract.ArrayType, stackitem.ArrayT // Block, Transaction, Contract
|
|
||||||
case "interop":
|
|
||||||
if name != "Interface" {
|
|
||||||
switch name {
|
|
||||||
case "Hash160":
|
|
||||||
return smartcontract.Hash160Type, stackitem.ByteArrayT
|
|
||||||
case "Hash256":
|
|
||||||
return smartcontract.Hash256Type, stackitem.ByteArrayT
|
|
||||||
case "PublicKey":
|
|
||||||
return smartcontract.PublicKeyType, stackitem.ByteArrayT
|
|
||||||
case "Signature":
|
|
||||||
return smartcontract.SignatureType, stackitem.ByteArrayT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return smartcontract.InteropInterfaceType, stackitem.InteropT
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch t := t.Underlying().(type) {
|
switch t := t.Underlying().(type) {
|
||||||
|
|
|
@ -24,6 +24,42 @@ import (
|
||||||
"go.uber.org/zap/zaptest"
|
"go.uber.org/zap/zaptest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestTypeConstantSize(t *testing.T) {
|
||||||
|
src := `package foo
|
||||||
|
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||||
|
var a %T // type declaration is always ok
|
||||||
|
func Main() interface{} {
|
||||||
|
return %#v
|
||||||
|
}`
|
||||||
|
|
||||||
|
t.Run("Hash160", func(t *testing.T) {
|
||||||
|
t.Run("good", func(t *testing.T) {
|
||||||
|
a := make(cinterop.Hash160, 20)
|
||||||
|
src := fmt.Sprintf(src, a, a)
|
||||||
|
eval(t, src, []byte(a))
|
||||||
|
})
|
||||||
|
t.Run("bad", func(t *testing.T) {
|
||||||
|
a := make(cinterop.Hash160, 19)
|
||||||
|
src := fmt.Sprintf(src, a, a)
|
||||||
|
_, err := compiler.Compile("foo.go", strings.NewReader(src))
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Hash256", func(t *testing.T) {
|
||||||
|
t.Run("good", func(t *testing.T) {
|
||||||
|
a := make(cinterop.Hash256, 32)
|
||||||
|
src := fmt.Sprintf(src, a, a)
|
||||||
|
eval(t, src, []byte(a))
|
||||||
|
})
|
||||||
|
t.Run("bad", func(t *testing.T) {
|
||||||
|
a := make(cinterop.Hash256, 31)
|
||||||
|
src := fmt.Sprintf(src, a, a)
|
||||||
|
_, err := compiler.Compile("foo.go", strings.NewReader(src))
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestFromAddress(t *testing.T) {
|
func TestFromAddress(t *testing.T) {
|
||||||
as1 := "NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN"
|
as1 := "NQRLhCpAru9BjGsMwk67vdMwmzKMRgsnnN"
|
||||||
addr1, err := address.StringToUint160(as1)
|
addr1, err := address.StringToUint160(as1)
|
||||||
|
|
Loading…
Reference in a new issue