diff --git a/pkg/compiler/analysis.go b/pkg/compiler/analysis.go index cc89fddbf..03f7bda06 100644 --- a/pkg/compiler/analysis.go +++ b/pkg/compiler/analysis.go @@ -17,7 +17,7 @@ var ( goBuiltins = []string{"len", "append", "panic", "make", "copy", "recover", "delete"} // Custom builtin utility functions. customBuiltins = []string{ - "FromAddress", "Equals", "Remove", + "Abort", "FromAddress", "Equals", "Remove", "ToBool", "ToBytes", "ToString", "ToInteger", } ) diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 8a2bd1673..30dae42be 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -1724,6 +1724,8 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) { c.emitStoreByIndex(varGlobal, c.exceptionIndex) case "delete": emit.Opcodes(c.prog.BinWriter, opcode.REMOVE) + case "Abort": + emit.Opcodes(c.prog.BinWriter, opcode.ABORT) case "Remove": if !isCompoundSlice(c.typeOf(expr.Args[0])) { c.prog.Err = errors.New("`Remove` supports only non-byte slices") diff --git a/pkg/compiler/interop_test.go b/pkg/compiler/interop_test.go index 135f1bc61..89624f06d 100644 --- a/pkg/compiler/interop_test.go +++ b/pkg/compiler/interop_test.go @@ -116,6 +116,18 @@ func TestFromAddress(t *testing.T) { }) } +func TestAbort(t *testing.T) { + src := `package foo + import "github.com/nspcc-dev/neo-go/pkg/interop/util" + func Main() int { + util.Abort() + return 1 + }` + v := vmAndCompile(t, src) + require.Error(t, v.Run()) + require.True(t, v.HasFailed()) +} + func spawnVM(t *testing.T, ic *interop.Context, src string) *vm.VM { b, di, err := compiler.CompileWithDebugInfo("foo.go", strings.NewReader(src)) require.NoError(t, err) diff --git a/pkg/interop/neogointernal/opcode.go b/pkg/interop/neogointernal/opcode.go index 2e18b936b..e96d0a1d4 100644 --- a/pkg/interop/neogointernal/opcode.go +++ b/pkg/interop/neogointernal/opcode.go @@ -1,5 +1,10 @@ package neogointernal +// Opcode0 emits opcode without arguments. +func Opcode0(op string) interface{} { + return nil +} + // Opcode1 emits opcode with 1 argument. func Opcode1(op string, arg interface{}) interface{} { return nil diff --git a/pkg/interop/types.go b/pkg/interop/types.go index 5ed473ccc..8025cc6be 100644 --- a/pkg/interop/types.go +++ b/pkg/interop/types.go @@ -1,5 +1,25 @@ package interop +const ( + // Hash160Len is the length of proper Hash160 in bytes, use it to + // sanitize input parameters. + Hash160Len = 20 + // Hash256Len is the length of proper Hash256 in bytes, use it to + // sanitize input parameters. + Hash256Len = 32 + // PublicKeyCompressedLen is the length of compressed public key (which + // is the most common public key type), use it to sanitize input + // parameters. + PublicKeyCompressedLen = 33 + // PublicKeyUncompressedLen is the length of uncompressed public key + // (but you're not likely to ever encounter that), use it to sanitize + // input parameters. + PublicKeyUncompressedLen = 65 + // SignatureLen is the length of standard signature, use it to sanitize + // input parameters. + SignatureLen = 64 +) + // Signature represents 64-byte signature. type Signature []byte diff --git a/pkg/interop/util/util.go b/pkg/interop/util/util.go index 7120759b7..79b2789bd 100644 --- a/pkg/interop/util/util.go +++ b/pkg/interop/util/util.go @@ -3,7 +3,16 @@ Package util contains some special useful functions that are provided by compile */ package util -import "github.com/nspcc-dev/neo-go/pkg/interop" +import ( + "github.com/nspcc-dev/neo-go/pkg/interop" + "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal" +) + +// Abort terminates current execution, unlike exception throwing with panic() it +// can't be recovered from. +func Abort() { + _ = neogointernal.Opcode0("ABORT") +} // FromAddress is an utility function that converts a Neo address to its hash // (160 bit BE value in a 20 byte slice). It can only be used for strings known