Merge pull request #1218 from nspcc-dev/neo3/interop/post-preview2_adjustment2
interop: post-preview2 adjustment, part 2
This commit is contained in:
commit
06f70e6a0b
11 changed files with 91 additions and 30 deletions
|
@ -68,6 +68,7 @@ var syscalls = map[string]map[string]Syscall{
|
|||
"CheckWitness": {"System.Runtime.CheckWitness", false},
|
||||
"Log": {"System.Runtime.Log", false},
|
||||
"Notify": {"System.Runtime.Notify", false},
|
||||
"Platform": {"System.Runtime.Platform", false},
|
||||
},
|
||||
"storage": {
|
||||
"ConvertContextToReadOnly": {"System.Storage.AsReadOnly", false},
|
||||
|
|
|
@ -10,7 +10,7 @@ func Concat(_ *interop.Context, v *vm.VM) error {
|
|||
return vm.EnumeratorConcat(v)
|
||||
}
|
||||
|
||||
// Create creates an enumerator from an array-like stack item.
|
||||
// Create creates an enumerator from an array-like or bytearray-like stack item.
|
||||
func Create(_ *interop.Context, v *vm.VM) error {
|
||||
return vm.EnumeratorCreate(v)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,11 @@ import (
|
|||
|
||||
// GasLeft returns remaining amount of GAS.
|
||||
func GasLeft(_ *interop.Context, v *vm.VM) error {
|
||||
v.Estack().PushVal(v.GasLimit - v.GasConsumed())
|
||||
if v.GasLimit == -1 {
|
||||
v.Estack().PushVal(v.GasLimit)
|
||||
} else {
|
||||
v.Estack().PushVal(v.GasLimit - v.GasConsumed())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -19,17 +19,7 @@ func CheckHashedWitness(ic *interop.Context, hash util.Uint160) (bool, error) {
|
|||
return checkScope(ic.DAO, tx, ic.ScriptGetter, hash)
|
||||
}
|
||||
|
||||
// only for non-Transaction types (Block, etc.)
|
||||
hashes, err := ic.Chain.GetScriptHashesForVerifying(ic.Tx)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "failed to get script hashes")
|
||||
}
|
||||
for _, v := range hashes {
|
||||
if hash.Equals(v) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
return false, errors.New("script container is not a transaction")
|
||||
}
|
||||
|
||||
func checkScope(d dao.DAO, tx *transaction.Transaction, v vm.ScriptHashGetter, hash util.Uint160) (bool, error) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||
|
@ -29,6 +30,8 @@ const (
|
|||
MaxTraceableBlocks = transaction.MaxValidUntilBlockIncrement
|
||||
// MaxEventNameLen is the maximum length of a name for event.
|
||||
MaxEventNameLen = 32
|
||||
// MaxNotificationSize is the maximum length of a runtime log message.
|
||||
MaxNotificationSize = 1024
|
||||
)
|
||||
|
||||
// StorageContext contains storing id and read/write flag, it's used as
|
||||
|
@ -250,6 +253,9 @@ func runtimeNotify(ic *interop.Context, v *vm.VM) error {
|
|||
if len(name) > MaxEventNameLen {
|
||||
return fmt.Errorf("event name must be less than %d", MaxEventNameLen)
|
||||
}
|
||||
if !utf8.Valid(name) {
|
||||
return errors.New("event name should be UTF8-encoded")
|
||||
}
|
||||
elem := v.Estack().Pop()
|
||||
args := elem.Array()
|
||||
// But it has to be serializable, otherwise we either have some broken
|
||||
|
@ -272,7 +278,14 @@ func runtimeNotify(ic *interop.Context, v *vm.VM) error {
|
|||
|
||||
// runtimeLog logs the message passed.
|
||||
func runtimeLog(ic *interop.Context, v *vm.VM) error {
|
||||
msg := fmt.Sprintf("%q", v.Estack().Pop().Bytes())
|
||||
state := v.Estack().Pop().Bytes()
|
||||
if len(state) > MaxNotificationSize {
|
||||
return fmt.Errorf("message length shouldn't exceed %v", MaxNotificationSize)
|
||||
}
|
||||
if !utf8.Valid(state) {
|
||||
return errors.New("log message should be UTF8-encoded")
|
||||
}
|
||||
msg := fmt.Sprintf("%q", state)
|
||||
ic.Log.Info("runtime log",
|
||||
zap.Stringer("script", v.GetCurrentScriptHash()),
|
||||
zap.String("logs", msg))
|
||||
|
|
|
@ -110,15 +110,17 @@ var systemInterops = []interop.Function{
|
|||
{Name: "System.Iterator.Values", Func: iterator.Values, Price: 400},
|
||||
{Name: "System.Json.Deserialize", Func: json.Deserialize, Price: 500000},
|
||||
{Name: "System.Json.Serialize", Func: json.Serialize, Price: 100000},
|
||||
{Name: "System.Runtime.CheckWitness", Func: runtime.CheckWitness, Price: 30000},
|
||||
{Name: "System.Runtime.CheckWitness", Func: runtime.CheckWitness, Price: 30000,
|
||||
RequiredFlags: smartcontract.AllowStates},
|
||||
{Name: "System.Runtime.GasLeft", Func: runtime.GasLeft, Price: 400},
|
||||
{Name: "System.Runtime.GetCallingScriptHash", Func: engineGetCallingScriptHash, Price: 400},
|
||||
{Name: "System.Runtime.GetEntryScriptHash", Func: engineGetEntryScriptHash, Price: 400},
|
||||
{Name: "System.Runtime.GetExecutingScriptHash", Func: engineGetExecutingScriptHash, Price: 400},
|
||||
{Name: "System.Runtime.GetInvocationCounter", Func: runtime.GetInvocationCounter, Price: 400},
|
||||
{Name: "System.Runtime.GetNotifications", Func: runtime.GetNotifications, Price: 10000},
|
||||
{Name: "System.Runtime.GetScriptContainer", Func: engineGetScriptContainer, Price: 250},
|
||||
{Name: "System.Runtime.GetTime", Func: runtimeGetTime, Price: 250,
|
||||
AllowedTriggers: trigger.Application},
|
||||
AllowedTriggers: trigger.Application, RequiredFlags: smartcontract.AllowStates},
|
||||
{Name: "System.Runtime.GetTrigger", Func: runtimeGetTrigger, Price: 250},
|
||||
{Name: "System.Runtime.Log", Func: runtimeLog, Price: 1000000, RequiredFlags: smartcontract.AllowNotify},
|
||||
{Name: "System.Runtime.Notify", Func: runtimeNotify, Price: 1000000, RequiredFlags: smartcontract.AllowNotify},
|
||||
|
|
|
@ -9,11 +9,11 @@ package enumerator
|
|||
// or structures that have values with no explicit keys.
|
||||
type Enumerator struct{}
|
||||
|
||||
// Create creates a new enumerator from the given items (slice or structure).
|
||||
// New enumerator points at index -1 of its items, so the user of it has to
|
||||
// advance it first with Next. This function uses `System.Enumerator.Create`
|
||||
// syscall.
|
||||
func Create(items []interface{}) Enumerator {
|
||||
// Create creates a new enumerator from the given items (slice, structure, byte
|
||||
// array and integer or boolean converted to byte array). New enumerator points
|
||||
// at index -1 of its items, so the user of it has to advance it first with Next.
|
||||
// This function uses `System.Enumerator.Create` syscall.
|
||||
func Create(items interface{}) Enumerator {
|
||||
return Enumerator{}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,10 +11,11 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/enumerator"
|
|||
// structure is similar in function to Neo .net framework's Iterator.
|
||||
type Iterator struct{}
|
||||
|
||||
// Create creates an iterator from the given items (array, struct or map). A new
|
||||
// iterator is set 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 {
|
||||
// Create creates an iterator from the given items (array, struct, map, byte
|
||||
// array or integer and boolean converted to byte array). A new iterator is set
|
||||
// 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{}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,3 +80,9 @@ func GetNotifications(h []byte) [][]interface{} {
|
|||
func GetInvocationCounter() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Platform returns the platform name, which is set to be `NEO`. This function uses
|
||||
// `System.Runtime.Platform` syscall.
|
||||
func Platform() []byte {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -126,12 +126,25 @@ func init() {
|
|||
|
||||
// EnumeratorCreate handles syscall System.Enumerator.Create.
|
||||
func EnumeratorCreate(v *VM) error {
|
||||
data := v.Estack().Pop().Array()
|
||||
v.Estack().Push(&Element{
|
||||
value: stackitem.NewInterop(&arrayWrapper{
|
||||
var interop interface{}
|
||||
switch t := v.Estack().Pop().value.(type) {
|
||||
case *stackitem.Array, *stackitem.Struct:
|
||||
interop = &arrayWrapper{
|
||||
index: -1,
|
||||
value: t.Value().([]stackitem.Item),
|
||||
}
|
||||
default:
|
||||
data, err := t.TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can not create enumerator from type %s: %v", t.Type(), err)
|
||||
}
|
||||
interop = &byteArrayWrapper{
|
||||
index: -1,
|
||||
value: data,
|
||||
}),
|
||||
}
|
||||
}
|
||||
v.Estack().Push(&Element{
|
||||
value: stackitem.NewInterop(interop),
|
||||
})
|
||||
|
||||
return nil
|
||||
|
@ -185,7 +198,14 @@ func IteratorCreate(v *VM) error {
|
|||
case *stackitem.Map:
|
||||
item = NewMapIterator(t)
|
||||
default:
|
||||
return errors.New("non-iterable type")
|
||||
data, err := t.TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("non-iterable type %s", t.Type())
|
||||
}
|
||||
item = stackitem.NewInterop(&byteArrayWrapper{
|
||||
index: -1,
|
||||
value: data,
|
||||
})
|
||||
}
|
||||
|
||||
v.Estack().Push(&Element{value: item})
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
|
@ -15,6 +17,11 @@ type (
|
|||
value []stackitem.Item
|
||||
}
|
||||
|
||||
byteArrayWrapper struct {
|
||||
index int
|
||||
value []byte
|
||||
}
|
||||
|
||||
concatEnum struct {
|
||||
current enumerator
|
||||
second enumerator
|
||||
|
@ -63,6 +70,23 @@ func (a *arrayWrapper) Key() stackitem.Item {
|
|||
return stackitem.Make(a.index)
|
||||
}
|
||||
|
||||
func (a *byteArrayWrapper) Next() bool {
|
||||
if next := a.index + 1; next < len(a.value) {
|
||||
a.index = next
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (a *byteArrayWrapper) Value() stackitem.Item {
|
||||
return stackitem.NewBigInteger(big.NewInt(int64(a.value[a.index])))
|
||||
}
|
||||
|
||||
func (a *byteArrayWrapper) Key() stackitem.Item {
|
||||
return stackitem.Make(a.index)
|
||||
}
|
||||
|
||||
func (c *concatEnum) Next() bool {
|
||||
if c.current.Next() {
|
||||
return true
|
||||
|
|
Loading…
Reference in a new issue