Merge pull request #1720 from nspcc-dev/compiler/syscall

Refactor syscall handing
This commit is contained in:
Roman Khimov 2021-02-24 19:31:52 +03:00 committed by GitHub
commit 46fbd940fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 166 additions and 128 deletions

View file

@ -277,8 +277,7 @@ func isSyscall(fun *funcScope) bool {
if fun.selector == nil || fun.pkg == nil || !isInteropPath(fun.pkg.Path()) {
return false
}
_, ok := syscalls[fun.pkg.Name()][fun.name]
return ok
return fun.pkg.Name() == "neogointernal" && strings.HasPrefix(fun.name, "Syscall")
}
const interopPrefix = "github.com/nspcc-dev/neo-go/pkg/interop"
@ -309,6 +308,13 @@ func canConvert(s string) bool {
// Currently there is a static list of function which are inlined,
// this may change in future.
func canInline(s string) bool {
return isNativeHelpersPath(s) ||
strings.HasPrefix(s, "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline")
if strings.HasPrefix(s, "github.com/nspcc-dev/neo-go/pkg/compiler/testdata/inline") {
return true
}
if !isInteropPath(s) {
return false
}
return !strings.HasPrefix(s[len(interopPrefix):], "/neogointernal") &&
!strings.HasPrefix(s[len(interopPrefix):], "/util") &&
!strings.HasPrefix(s[len(interopPrefix):], "/convert")
}

View file

@ -872,7 +872,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.saveSequencePoint(n)
args := transformArgs(n.Fun, n.Args)
args := transformArgs(f, n.Fun, n.Args)
// Handle the arguments
for _, arg := range args {
@ -888,7 +888,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
}
}
// Do not swap for builtin functions.
if !isBuiltin {
if !isBuiltin && (f != nil && !isSyscall(f)) {
typ, ok := c.typeOf(n.Fun).(*types.Signature)
if ok && typ.Variadic() && !n.Ellipsis.IsValid() {
// pack variadic args into an array only if last argument is not of form `...`
@ -932,7 +932,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.emittedEvents[name] = append(c.emittedEvents[name], params)
}
}
c.convertSyscall(n, f.pkg.Name(), f.name)
c.convertSyscall(n)
default:
emit.Call(c.prog.BinWriter, opcode.CALLL, f.label)
}
@ -1523,12 +1523,13 @@ func (c *codegen) getByteArray(expr ast.Expr) []byte {
}
}
func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
syscall, ok := syscalls[api][name]
if !ok {
c.prog.Err = fmt.Errorf("unknown VM syscall api: %s.%s", api, name)
return
func (c *codegen) convertSyscall(expr *ast.CallExpr) {
for _, arg := range expr.Args[1:] {
ast.Walk(c, arg)
}
c.emitReverse(len(expr.Args) - 1)
tv := c.typeAndValueOf(expr.Args[0])
syscall := constant.StringVal(tv.Value)
emit.Syscall(c.prog.BinWriter, syscall)
// This NOP instruction is basically not needed, but if we do, we have a
@ -1714,12 +1715,15 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
// so there is no need to push parameters on stack and perform an actual call
// 2. With panic, generated code depends on if argument was nil or a string so
// it should be handled accordingly.
func transformArgs(fun ast.Expr, args []ast.Expr) []ast.Expr {
func transformArgs(fs *funcScope, fun ast.Expr, args []ast.Expr) []ast.Expr {
switch f := fun.(type) {
case *ast.SelectorExpr:
if f.Sel.Name == "FromAddress" {
return args[1:]
}
if fs != nil && isSyscall(fs) {
return nil
}
case *ast.Ident:
switch f.Name {
case "make", "copy", "append":

View file

@ -131,6 +131,11 @@ func (c *codegen) countLocalsInline(decl *ast.FuncDecl, pkg *types.Package, f *f
return false
}
if inner, ok := c.funcs[name]; ok && canInline(name) {
sig, ok := c.typeOf(n.Fun).(*types.Signature)
if !ok {
info := c.buildInfo.program.Package(pkg.Path())
sig = info.Types[n.Fun].Type.(*types.Signature)
}
for i := range n.Args {
switch n.Args[i].(type) {
case *ast.Ident:
@ -139,6 +144,10 @@ func (c *codegen) countLocalsInline(decl *ast.FuncDecl, pkg *types.Package, f *f
size++
}
}
// Variadic with direct var args.
if sig.Variadic() && !n.Ellipsis.IsValid() {
size++
}
innerSz, _ := c.countLocalsInline(inner.decl, inner.pkg, inner)
size += innerSz
}

View file

@ -1,66 +0,0 @@
package compiler
import "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
// All lists are sorted, keep 'em this way, please.
var syscalls = map[string]map[string]string{
"binary": {
"Atoi": interopnames.SystemBinaryAtoi,
"Base58Decode": interopnames.SystemBinaryBase58Decode,
"Base58Encode": interopnames.SystemBinaryBase58Encode,
"Base64Decode": interopnames.SystemBinaryBase64Decode,
"Base64Encode": interopnames.SystemBinaryBase64Encode,
"Deserialize": interopnames.SystemBinaryDeserialize,
"Itoa": interopnames.SystemBinaryItoa,
"Serialize": interopnames.SystemBinarySerialize,
},
"contract": {
"Call": interopnames.SystemContractCall,
"CreateMultisigAccount": interopnames.SystemContractCreateMultisigAccount,
"CreateStandardAccount": interopnames.SystemContractCreateStandardAccount,
"IsStandard": interopnames.SystemContractIsStandard,
"GetCallFlags": interopnames.SystemContractGetCallFlags,
},
"crypto": {
"ECDsaSecp256k1Verify": interopnames.NeoCryptoVerifyWithECDsaSecp256k1,
"ECDSASecp256k1CheckMultisig": interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1,
"ECDsaSecp256r1Verify": interopnames.NeoCryptoVerifyWithECDsaSecp256r1,
"ECDSASecp256r1CheckMultisig": interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1,
"RIPEMD160": interopnames.NeoCryptoRIPEMD160,
"SHA256": interopnames.NeoCryptoSHA256,
},
"iterator": {
"Create": interopnames.SystemIteratorCreate,
"Next": interopnames.SystemIteratorNext,
"Value": interopnames.SystemIteratorValue,
},
"json": {
"Deserialize": interopnames.SystemJSONDeserialize,
"Serialize": interopnames.SystemJSONSerialize,
},
"runtime": {
"GasLeft": interopnames.SystemRuntimeGasLeft,
"GetInvocationCounter": interopnames.SystemRuntimeGetInvocationCounter,
"GetCallingScriptHash": interopnames.SystemRuntimeGetCallingScriptHash,
"GetEntryScriptHash": interopnames.SystemRuntimeGetEntryScriptHash,
"GetExecutingScriptHash": interopnames.SystemRuntimeGetExecutingScriptHash,
"GetNotifications": interopnames.SystemRuntimeGetNotifications,
"GetScriptContainer": interopnames.SystemRuntimeGetScriptContainer,
"GetTime": interopnames.SystemRuntimeGetTime,
"GetTrigger": interopnames.SystemRuntimeGetTrigger,
"CheckWitness": interopnames.SystemRuntimeCheckWitness,
"Log": interopnames.SystemRuntimeLog,
"Notify": interopnames.SystemRuntimeNotify,
"Platform": interopnames.SystemRuntimePlatform,
},
"storage": {
"ConvertContextToReadOnly": interopnames.SystemStorageAsReadOnly,
"Delete": interopnames.SystemStorageDelete,
"Find": interopnames.SystemStorageFind,
"Get": interopnames.SystemStorageGet,
"GetContext": interopnames.SystemStorageGetContext,
"GetReadOnlyContext": interopnames.SystemStorageGetReadOnlyContext,
"Put": interopnames.SystemStoragePut,
"PutEx": interopnames.SystemStoragePutEx,
},
}

View file

@ -3,52 +3,56 @@ Package binary provides binary serialization routines.
*/
package binary
import (
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
)
// Serialize serializes any given item into a byte slice. It works for all
// regular VM types (not ones from interop package) and allows to save them in
// storage or pass into Notify and then Deserialize them on the next run or in
// the external event receiver. It uses `System.Binary.Serialize` syscall.
func Serialize(item interface{}) []byte {
return nil
return neogointernal.Syscall1("System.Binary.Serialize", item).([]byte)
}
// Deserialize unpacks previously serialized value from a byte slice, it's the
// opposite of Serialize. It uses `System.Binary.Deserialize` syscall.
func Deserialize(b []byte) interface{} {
return nil
return neogointernal.Syscall1("System.Binary.Deserialize", b)
}
// Base64Encode encodes given byte slice into a base64 string and returns byte
// representation of this string. It uses `System.Binary.Base64Encode` interop.
func Base64Encode(b []byte) string {
return ""
return neogointernal.Syscall1("System.Binary.Base64Encode", b).(string)
}
// Base64Decode decodes given base64 string represented as a byte slice into
// byte slice. It uses `System.Binary.Base64Decode` interop.
func Base64Decode(b []byte) []byte {
return nil
return neogointernal.Syscall1("System.Binary.Base64Decode", b).([]byte)
}
// Base58Encode encodes given byte slice into a base58 string and returns byte
// representation of this string. It uses `System.Binary.Base58Encode` syscall.
func Base58Encode(b []byte) string {
return ""
return neogointernal.Syscall1("System.Binary.Base58Encode", b).(string)
}
// Base58Decode decodes given base58 string represented as a byte slice into
// a new byte slice. It uses `System.Binary.Base58Decode` syscall.
func Base58Decode(b []byte) []byte {
return nil
return neogointernal.Syscall1("System.Binary.Base64Decode", b).([]byte)
}
// Itoa converts num in a given base to string. Base should be either 10 or 16.
// It uses `System.Binary.Itoa` syscall.
func Itoa(num int, base int) string {
return ""
return neogointernal.Syscall2("System.Binary.Itoa", num, base).(string)
}
// Atoi converts string to a number in a given base. Base should be either 10 or 16.
// It uses `System.Binary.Atoi` syscall.
func Atoi(s string, base int) int {
return 0
return neogointernal.Syscall2("System.Binary.Atoi", s, base).(int)
}

View file

@ -3,7 +3,10 @@ Package contract provides functions to work with contracts.
*/
package contract
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"
)
// CallFlag specifies valid call flags.
type CallFlag byte
@ -24,26 +27,26 @@ const (
// IsStandard checks if contract with provided hash is a standard signature/multisig contract.
// This function uses `System.Contract.IsStandard` syscall.
func IsStandard(h interop.Hash160) bool {
return false
return neogointernal.Syscall1("System.Contract.IsStandard", h).(bool)
}
// CreateMultisigAccount calculates script hash of an m out of n multisignature
// script using given m and a set of public keys bytes. This function uses
// `System.Contract.CreateMultisigAccount` syscall.
func CreateMultisigAccount(m int, pubs []interop.PublicKey) []byte {
return nil
return neogointernal.Syscall1("System.Contract.CreateMultisigAccount", pubs).([]byte)
}
// CreateStandardAccount calculates script hash of a given public key.
// This function uses `System.Contract.CreateStandardAccount` syscall.
func CreateStandardAccount(pub interop.PublicKey) []byte {
return nil
return neogointernal.Syscall1("System.Contract.CreateStandardAccount", pub).([]byte)
}
// GetCallFlags returns calling flags which execution context was created with.
// This function uses `System.Contract.GetCallFlags` syscall.
func GetCallFlags() int64 {
return 0
return neogointernal.Syscall0("System.Contract.GetFlags").(int64)
}
// Call executes previously deployed blockchain contract with specified hash
@ -51,5 +54,5 @@ func GetCallFlags() int64 {
// It returns whatever this contract returns. This function uses
// `System.Contract.Call` syscall.
func Call(scriptHash interop.Hash160, method string, f CallFlag, args ...interface{}) interface{} {
return nil
return neogointernal.Syscall4("System.Contract.Call", scriptHash, method, f, args)
}

View file

@ -3,38 +3,41 @@ Package crypto provides an interface to cryptographic syscalls.
*/
package crypto
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"
)
// SHA256 computes SHA256 hash of b. It uses `Neo.Crypto.SHA256` syscall.
func SHA256(b []byte) interop.Hash256 {
return nil
return neogointernal.Syscall1("Neo.Crypto.SHA256", b).(interop.Hash256)
}
// RIPEMD160 computes RIPEMD160 hash of b. It uses `Neo.Crypto.RIPEMD160` syscall.
func RIPEMD160(b []byte) interop.Hash160 {
return nil
return neogointernal.Syscall1("Neo.Crypto.RIPEMD160", b).(interop.Hash160)
}
// ECDsaSecp256r1Verify checks that sig is correct msg's signature for a given pub
// (serialized public key). It uses `Neo.Crypto.VerifyWithECDsaSecp256r1` syscall.
func ECDsaSecp256r1Verify(msg []byte, pub interop.PublicKey, sig interop.Signature) bool {
return false
return neogointernal.Syscall3("Neo.Crypto.VerifyWithECDsaSecp256r1", msg, pub, sig).(bool)
}
// ECDsaSecp256k1Verify checks that sig is correct msg's signature for a given pub
// (serialized public key). It uses `Neo.Crypto.VerifyWithECDsaSecp256k1` syscall.
func ECDsaSecp256k1Verify(msg []byte, pub interop.PublicKey, sig interop.Signature) bool {
return false
return neogointernal.Syscall3("Neo.Crypto.VerifyWithECDsaSecp256k1", msg, pub, sig).(bool)
}
// ECDSASecp256r1CheckMultisig checks multiple ECDSA signatures at once. It uses
// `Neo.Crypto.CheckMultisigWithECDsaSecp256r1` syscall.
func ECDSASecp256r1CheckMultisig(msg []byte, pubs []interop.PublicKey, sigs []interop.Signature) bool {
return false
return neogointernal.Syscall3("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", msg, pubs, sigs).(bool)
}
// ECDSASecp256k1CheckMultisig checks multiple ECDSA signatures at once. It uses
// `Neo.Crypto.CheckMultisigWithECDsaSecp256k1` syscall.
func ECDSASecp256k1CheckMultisig(msg []byte, pubs []interop.PublicKey, sigs []interop.Signature) bool {
return false
return neogointernal.Syscall3("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", msg, pubs, sigs).(bool)
}

View file

@ -3,6 +3,8 @@ Package iterator provides functions to work with Neo iterators.
*/
package iterator
import "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
// Iterator represents a Neo iterator, it's an opaque data structure that can
// be properly created by Create or storage.Find. Unlike enumerators, iterators
// range over key-value pairs, so it's convenient to use them for maps. This
@ -14,14 +16,14 @@ type Iterator struct{}
// to point at element -1, so to access its first element you need to call Next
// first. This function uses `System.Iterator.Create` syscall.
func Create(items interface{}) Iterator {
return Iterator{}
return neogointernal.Syscall1("System.Iterator.Create", items).(Iterator)
}
// Next advances the iterator returning true if it is was successful (and you
// can use Key or Value) and false otherwise (and there are no more elements in
// this Iterator). This function uses `System.Iterator.Next` syscall.
func Next(it Iterator) bool {
return true
return neogointernal.Syscall1("System.Iterator.Next", it).(bool)
}
// Value returns iterator's current value. It's only valid to call after
@ -30,5 +32,5 @@ func Next(it Iterator) bool {
// For maps the result can be casted to a slice of 2 elements: key and value.
// For storage iterators refer to `storage.FindFlags` documentation.
func Value(it Iterator) interface{} {
return nil
return neogointernal.Syscall1("System.Iterator.Value", it)
}

View file

@ -3,6 +3,8 @@ Package json provides various JSON serialization/deserialization routines.
*/
package json
import "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
// ToJSON serializes value to json. It uses `System.Json.Serialize` syscall.
// Serialization format is the following:
// []byte -> base64 string
@ -13,7 +15,7 @@ package json
// []interface{} -> json array
// map[type1]type2 -> json object with string keys marshaled as strings (not base64).
func ToJSON(item interface{}) []byte {
return nil
return neogointernal.Syscall1("System.Json.Serialize", item).([]byte)
}
// FromJSON deserializes value from json. It uses `System.Json.Deserialize` syscall.
@ -24,5 +26,5 @@ func ToJSON(item interface{}) []byte {
// arrays -> []interface{}
// maps -> map[string]interface{}
func FromJSON(data []byte) interface{} {
return nil
return neogointernal.Syscall1("System.Json.Deserialize", data).(interface{})
}

View file

@ -0,0 +1,46 @@
package neogointernal
// Syscall0 performs syscall with 0 arguments.
func Syscall0(name string) interface{} {
return nil
}
// Syscall0NoReturn performs syscall with 0 arguments.
func Syscall0NoReturn(name string) {
}
// Syscall1 performs syscall with 1 arguments.
func Syscall1(name string, arg interface{}) interface{} {
return nil
}
// Syscall1NoReturn performs syscall with 1 arguments.
func Syscall1NoReturn(name string, arg interface{}) {
}
// Syscall2 performs syscall with 2 arguments.
func Syscall2(name string, arg1, arg2 interface{}) interface{} {
return nil
}
// Syscall2NoReturn performs syscall with 2 arguments.
func Syscall2NoReturn(name string, arg1, arg2 interface{}) {
}
// Syscall3 performs syscall with 3 arguments.
func Syscall3(name string, arg1, arg2, arg3 interface{}) interface{} {
return nil
}
// Syscall3NoReturn performs syscall with 3 arguments.
func Syscall3NoReturn(name string, arg1, arg2, arg3 interface{}) {
}
// Syscall4 performs syscall with 4 arguments.
func Syscall4(name string, arg1, arg2, arg3, arg4 interface{}) interface{} {
return nil
}
// Syscall4NoReturn performs syscall with 4 arguments.
func Syscall4NoReturn(name string, arg1, arg2, arg3, arg4 interface{}) {
}

View file

@ -3,6 +3,7 @@ package runtime
import (
"github.com/nspcc-dev/neo-go/pkg/interop"
"github.com/nspcc-dev/neo-go/pkg/interop/native/ledger"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
)
// GetScriptContainer returns the transaction that initially triggered current
@ -10,7 +11,7 @@ import (
// this execution goes. This function uses
// `System.Runtime.GetScriptContainer` syscall.
func GetScriptContainer() *ledger.Transaction {
return &ledger.Transaction{}
return neogointernal.Syscall0("System.Runtime.GetScriptContainer").(*ledger.Transaction)
}
// GetExecutingScriptHash returns script hash (160 bit in BE form represented
@ -19,7 +20,7 @@ func GetScriptContainer() *ledger.Transaction {
// different contract. This function uses
// `System.Runtime.GetExecutingScriptHash` syscall.
func GetExecutingScriptHash() interop.Hash160 {
return nil
return neogointernal.Syscall0("System.Runtime.GetExecutingScriptHash").(interop.Hash160)
}
// GetCallingScriptHash returns script hash (160 bit in BE form represented
@ -28,7 +29,7 @@ func GetExecutingScriptHash() interop.Hash160 {
// above the GetExecutingScriptHash in the call stack. It uses
// `System.Runtime.GetCallingScriptHash` syscall.
func GetCallingScriptHash() interop.Hash160 {
return nil
return neogointernal.Syscall0("System.Runtime.GetCallingScriptHash").(interop.Hash160)
}
// GetEntryScriptHash returns script hash (160 bit in BE form represented
@ -37,5 +38,5 @@ func GetCallingScriptHash() interop.Hash160 {
// GetScriptContainer) execution from the start. This function uses
// `System.Runtime.GetEntryScriptHash` syscall.
func GetEntryScriptHash() interop.Hash160 {
return nil
return neogointernal.Syscall0("System.Runtime.GetEntryScriptHash").(interop.Hash160)
}

View file

@ -4,7 +4,10 @@ It has similar function to Runtime class in .net framwork for Neo.
*/
package runtime
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"
)
// Trigger values to compare with GetTrigger result.
const (
@ -18,13 +21,15 @@ const (
// slice) or key (compressed serialized 33-byte form) is one of the signers of
// this invocation. It uses `System.Runtime.CheckWitness` syscall.
func CheckWitness(hashOrKey []byte) bool {
return true
return neogointernal.Syscall1("System.Runtime.CheckWitness", hashOrKey).(bool)
}
// Log instructs VM to log the given message. It's mostly used for debugging
// purposes as these messages are not saved anywhere normally and usually are
// only visible in the VM logs. This function uses `System.Runtime.Log` syscall.
func Log(message string) {}
func Log(message string) {
neogointernal.Syscall1NoReturn("System.Runtime.Log", message)
}
// Notify sends a notification (collecting all arguments in an array) to the
// executing environment. Unlike Log it can accept any data along with the event name
@ -32,7 +37,9 @@ func Log(message string) {}
// part of contract's API to external systems, these events can be monitored
// from outside and act upon accordingly. This function uses
// `System.Runtime.Notify` syscall.
func Notify(name string, arg ...interface{}) {}
func Notify(name string, args ...interface{}) {
neogointernal.Syscall2NoReturn("System.Runtime.Notify", name, args)
}
// GetTime returns the timestamp of the most recent block. Note that when running
// script in test mode this would be the last accepted (persisted) block in the
@ -40,7 +47,7 @@ func Notify(name string, arg ...interface{}) {}
// time of this (currently being processed) block. This function uses
// `System.Runtime.GetTime` syscall.
func GetTime() int {
return 0
return neogointernal.Syscall0("System.Runtime.GetTime").(int)
}
// GetTrigger returns the smart contract invocation trigger which can be either
@ -50,13 +57,13 @@ func GetTime() int {
// not available when running with verification trigger. This function uses
// `System.Runtime.GetTrigger` syscall.
func GetTrigger() byte {
return 0x00
return neogointernal.Syscall0("System.Runtime.GetTrigger").(byte)
}
// GasLeft returns the amount of gas available for the current execution.
// This function uses `System.Runtime.GasLeft` syscall.
func GasLeft() int64 {
return 0
return neogointernal.Syscall0("System.Runtime.GasLeft").(int64)
}
// GetNotifications returns notifications emitted by contract h.
@ -64,17 +71,17 @@ func GasLeft() int64 {
// [ scripthash of notification's contract , emitted item ].
// This function uses `System.Runtime.GetNotifications` syscall.
func GetNotifications(h interop.Hash160) [][]interface{} {
return nil
return neogointernal.Syscall1("System.Runtime.GetNotifications", h).([][]interface{})
}
// GetInvocationCounter returns how many times current contract was invoked during current tx execution.
// This function uses `System.Runtime.GetInvocationCounter` syscall.
func GetInvocationCounter() int {
return 0
return neogointernal.Syscall0("System.Runtime.GetInvocationCounter").(int)
}
// Platform returns the platform name, which is set to be `NEO`. This function uses
// `System.Runtime.Platform` syscall.
func Platform() []byte {
return nil
return neogointernal.Syscall0("System.Runtime.Platform").([]byte)
}

View file

@ -6,7 +6,10 @@ contract.
*/
package storage
import "github.com/nspcc-dev/neo-go/pkg/interop/iterator"
import (
"github.com/nspcc-dev/neo-go/pkg/interop/iterator"
"github.com/nspcc-dev/neo-go/pkg/interop/neogointernal"
)
// Context represents storage context that is mandatory for Put/Get/Delete
// operations. It's an opaque type that can only be created properly by
@ -39,46 +42,60 @@ const (
// writing capability turned off, so that you could only invoke Get and Find
// using this new Context. If Context is already read-only this function is a
// no-op. It uses `System.Storage.AsReadOnly` syscall.
func ConvertContextToReadOnly(ctx Context) Context { return Context{} }
func ConvertContextToReadOnly(ctx Context) Context {
return neogointernal.Syscall0("System.Storage.AsReadOnly").(Context)
}
// GetContext returns current contract's (that invokes this function) storage
// context. It uses `System.Storage.GetContext` syscall.
func GetContext() Context { return Context{} }
func GetContext() Context {
return neogointernal.Syscall0("System.Storage.GetContext").(Context)
}
// GetReadOnlyContext returns current contract's (that invokes this function)
// storage context in read-only mode, you can use this context for Get and Find
// functions, but using it for Put and Delete will fail. It uses
// `System.Storage.GetReadOnlyContext` syscall.
func GetReadOnlyContext() Context { return Context{} }
func GetReadOnlyContext() Context {
return neogointernal.Syscall0("System.Storage.GetReadOnlyContext").(Context)
}
// Put saves given value with given key in the storage using given Context.
// Even though it accepts interface{} for both, you can only pass simple types
// there like string, []byte, int or bool (not structures or slices of more
// complex types). To put more complex types there serialize them first using
// runtime.Serialize. This function uses `System.Storage.Put` syscall.
func Put(ctx Context, key interface{}, value interface{}) {}
func Put(ctx Context, key interface{}, value interface{}) {
neogointernal.Syscall3NoReturn("System.Storage.Put", ctx, key, value)
}
// PutEx is an advanced version of Put which saves given value with given key
// and given ReadOnly flag in the storage using given Context. `flag` argument
// can either be odd for constant storage items or even for variable storage items.
// Refer to Put function description for details on how to pass the remaining
// arguments. This function uses `System.Storage.PutEx` syscall.
func PutEx(ctx Context, key interface{}, value interface{}, flag int64) {}
func PutEx(ctx Context, key interface{}, value interface{}, flag int64) {
neogointernal.Syscall4NoReturn("System.Storage.PutEx", ctx, key, value, flag)
}
// Get retrieves value stored for the given key using given Context. See Put
// documentation on possible key and value types. If the value is not present in
// the database it returns nil. This function uses `System.Storage.Get` syscall.
func Get(ctx Context, key interface{}) interface{} { return nil }
func Get(ctx Context, key interface{}) interface{} {
return neogointernal.Syscall2("System.Storage.Get", ctx, key)
}
// Delete removes key-value pair from storage by the given key using given
// Context. See Put documentation on possible key types. This function uses
// `System.Storage.Delete` syscall.
func Delete(ctx Context, key interface{}) {}
func Delete(ctx Context, key interface{}) {
neogointernal.Syscall2NoReturn("System.Storage.Delete", ctx, key)
}
// Find returns an iterator.Iterator over key-value pairs in the given Context
// that match the given key (contain it as a prefix). See Put documentation on
// possible key types and iterator package documentation on how to use the
// returned value. This function uses `System.Storage.Find` syscall.
func Find(ctx Context, key interface{}, options FindFlags) iterator.Iterator {
return iterator.Iterator{}
return neogointernal.Syscall3("System.Storage.Find", ctx, key, options).(iterator.Iterator)
}