mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-22 09:19:08 +00:00
commit
895a0ae624
7 changed files with 70 additions and 33 deletions
12
ROADMAP.md
12
ROADMAP.md
|
@ -68,4 +68,14 @@ event-based waiter fallbacks to the old way of block monitoring with
|
||||||
`block_added` notifications subscription.
|
`block_added` notifications subscription.
|
||||||
|
|
||||||
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
|
Removal of stale RPC server compatibility code from `waiter.EventWaiter` is
|
||||||
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
scheduled for Jun-Jul 2024 (~0.107.0 release).
|
||||||
|
|
||||||
|
## Dump*Slot() methods of `vm.Context`
|
||||||
|
|
||||||
|
The following new methods have been exposed to give access to VM context slot contents
|
||||||
|
with greater flexibility:
|
||||||
|
- `ArgumentsSlot`
|
||||||
|
- `LocalsSlot`
|
||||||
|
- `StaticsSlot`.
|
||||||
|
|
||||||
|
Removal of the `Dump*Slot()` methods are scheduled for the 0.108.0 release.
|
|
@ -695,11 +695,11 @@ func handleSlots(c *cli.Context) error {
|
||||||
var rawSlot string
|
var rawSlot string
|
||||||
switch c.Command.Name {
|
switch c.Command.Name {
|
||||||
case "sslot":
|
case "sslot":
|
||||||
rawSlot = vmCtx.DumpStaticSlot()
|
rawSlot = dumpSlot(vmCtx.StaticsSlot())
|
||||||
case "lslot":
|
case "lslot":
|
||||||
rawSlot = vmCtx.DumpLocalSlot()
|
rawSlot = dumpSlot(vmCtx.LocalsSlot())
|
||||||
case "aslot":
|
case "aslot":
|
||||||
rawSlot = vmCtx.DumpArgumentsSlot()
|
rawSlot = dumpSlot(vmCtx.ArgumentsSlot())
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown slot")
|
return errors.New("unknown slot")
|
||||||
}
|
}
|
||||||
|
@ -707,6 +707,14 @@ func handleSlots(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func dumpSlot(s *vm.Slot) string {
|
||||||
|
if s == nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
|
b, _ := json.MarshalIndent(s, "", " ")
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
// prepareVM retrieves --historic flag from context (if set) and resets app state
|
// prepareVM retrieves --historic flag from context (if set) and resets app state
|
||||||
// (to the specified historic height if given).
|
// (to the specified historic height if given).
|
||||||
func prepareVM(c *cli.Context, tx *transaction.Transaction) error {
|
func prepareVM(c *cli.Context, tx *transaction.Transaction) error {
|
||||||
|
|
|
@ -30,7 +30,7 @@ type scriptContext struct {
|
||||||
// Evaluation stack pointer.
|
// Evaluation stack pointer.
|
||||||
estack *Stack
|
estack *Stack
|
||||||
|
|
||||||
static slot
|
static Slot
|
||||||
|
|
||||||
// Script hash of the prog.
|
// Script hash of the prog.
|
||||||
scriptHash util.Uint160
|
scriptHash util.Uint160
|
||||||
|
@ -65,8 +65,8 @@ type Context struct {
|
||||||
|
|
||||||
sc *scriptContext
|
sc *scriptContext
|
||||||
|
|
||||||
local slot
|
local Slot
|
||||||
arguments slot
|
arguments Slot
|
||||||
|
|
||||||
// Exception context stack.
|
// Exception context stack.
|
||||||
tryStack Stack
|
tryStack Stack
|
||||||
|
@ -278,22 +278,26 @@ func (c *Context) IsDeployed() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpStaticSlot returns json formatted representation of the given slot.
|
// DumpStaticSlot returns json formatted representation of the given slot.
|
||||||
|
// Deprecated: to be removed in next version. Use [Context.StaticsSlot] instead.
|
||||||
func (c *Context) DumpStaticSlot() string {
|
func (c *Context) DumpStaticSlot() string {
|
||||||
return dumpSlot(&c.sc.static)
|
return dumpSlot(&c.sc.static)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpLocalSlot returns json formatted representation of the given slot.
|
// DumpLocalSlot returns json formatted representation of the given slot.
|
||||||
|
// Deprecated: to be removed in next version. Use [Context.LocalsSlot] instead.
|
||||||
func (c *Context) DumpLocalSlot() string {
|
func (c *Context) DumpLocalSlot() string {
|
||||||
return dumpSlot(&c.local)
|
return dumpSlot(&c.local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpArgumentsSlot returns json formatted representation of the given slot.
|
// DumpArgumentsSlot returns json formatted representation of the given slot.
|
||||||
|
// Deprecated: to be removed in next version. Use [Context.ArgumentsSlot] instead.
|
||||||
func (c *Context) DumpArgumentsSlot() string {
|
func (c *Context) DumpArgumentsSlot() string {
|
||||||
return dumpSlot(&c.arguments)
|
return dumpSlot(&c.arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dumpSlot returns json formatted representation of the given slot.
|
// dumpSlot returns json formatted representation of the given slot.
|
||||||
func dumpSlot(s *slot) string {
|
// Deprecated: to be removed in next version.
|
||||||
|
func dumpSlot(s *Slot) string {
|
||||||
if s == nil || *s == nil {
|
if s == nil || *s == nil {
|
||||||
return "[]"
|
return "[]"
|
||||||
}
|
}
|
||||||
|
@ -354,3 +358,18 @@ func DynamicOnUnload(v *VM, ctx *Context, commit bool) error {
|
||||||
func (c *Context) BreakPoints() []int {
|
func (c *Context) BreakPoints() []int {
|
||||||
return slices.Clone(c.sc.breakPoints)
|
return slices.Clone(c.sc.breakPoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ArgumentsSlot returns the arguments slot of Context.
|
||||||
|
func (c *Context) ArgumentsSlot() *Slot {
|
||||||
|
return &c.arguments
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalsSlot returns the local slot of Context.
|
||||||
|
func (c *Context) LocalsSlot() *Slot {
|
||||||
|
return &c.local
|
||||||
|
}
|
||||||
|
|
||||||
|
// StaticsSlot returns the static slot of Context.
|
||||||
|
func (c *Context) StaticsSlot() *Slot {
|
||||||
|
return &c.sc.static
|
||||||
|
}
|
||||||
|
|
|
@ -240,7 +240,7 @@ func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
||||||
compareItemArrays(t, expected, actual.Len(), func(i int) stackitem.Item { return actual.Peek(i).Item() })
|
compareItemArrays(t, expected, actual.Len(), func(i int) stackitem.Item { return actual.Peek(i).Item() })
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareSlots(t *testing.T, expected []vmUTStackItem, actual slot) {
|
func compareSlots(t *testing.T, expected []vmUTStackItem, actual Slot) {
|
||||||
if actual == nil && len(expected) == 0 {
|
if actual == nil && len(expected) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// slot is a fixed-size slice of stack items.
|
// Slot is a fixed-size slice of stack items.
|
||||||
type slot []stackitem.Item
|
type Slot []stackitem.Item
|
||||||
|
|
||||||
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
||||||
func (s *slot) init(n int, rc *refCounter) {
|
func (s *Slot) init(n int, rc *refCounter) {
|
||||||
if *s != nil {
|
if *s != nil {
|
||||||
panic("already initialized")
|
panic("already initialized")
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@ func (s *slot) init(n int, rc *refCounter) {
|
||||||
*rc += refCounter(n) // Virtual "Null" elements.
|
*rc += refCounter(n) // Virtual "Null" elements.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets i-th storage slot.
|
// set sets i-th storage slot.
|
||||||
func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
func (s Slot) set(i int, item stackitem.Item, refs *refCounter) {
|
||||||
if s[i] == item {
|
if s[i] == item {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -29,30 +29,30 @@ func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the item contained in the i-th slot.
|
// Get returns the item contained in the i-th slot.
|
||||||
func (s slot) Get(i int) stackitem.Item {
|
func (s Slot) Get(i int) stackitem.Item {
|
||||||
if item := s[i]; item != nil {
|
if item := s[i]; item != nil {
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
return stackitem.Null{}
|
return stackitem.Null{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearRefs removes all slot variables from the reference counter.
|
// clearRefs removes all slot variables from the reference counter.
|
||||||
func (s slot) ClearRefs(refs *refCounter) {
|
func (s Slot) clearRefs(refs *refCounter) {
|
||||||
for _, item := range s {
|
for _, item := range s {
|
||||||
refs.Remove(item)
|
refs.Remove(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the slot size.
|
// Size returns the slot size.
|
||||||
func (s slot) Size() int {
|
func (s Slot) Size() int {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
panic("not initialized")
|
return 0
|
||||||
}
|
}
|
||||||
return len(s)
|
return len(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the JSON marshalling interface.
|
// MarshalJSON implements the JSON marshalling interface.
|
||||||
func (s slot) MarshalJSON() ([]byte, error) {
|
func (s Slot) MarshalJSON() ([]byte, error) {
|
||||||
arr := make([]json.RawMessage, len(s))
|
arr := make([]json.RawMessage, len(s))
|
||||||
for i := range s {
|
for i := range s {
|
||||||
data, err := stackitem.ToJSONWithTypes(s[i])
|
data, err := stackitem.ToJSONWithTypes(s[i])
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
|
|
||||||
func TestSlot_Get(t *testing.T) {
|
func TestSlot_Get(t *testing.T) {
|
||||||
rc := newRefCounter()
|
rc := newRefCounter()
|
||||||
var s slot
|
var s Slot
|
||||||
require.Panics(t, func() { s.Size() })
|
require.Equal(t, 0, s.Size())
|
||||||
|
|
||||||
s.init(3, rc)
|
s.init(3, rc)
|
||||||
require.Equal(t, 3, s.Size())
|
require.Equal(t, 3, s.Size())
|
||||||
|
@ -21,7 +21,7 @@ func TestSlot_Get(t *testing.T) {
|
||||||
item := s.Get(2)
|
item := s.Get(2)
|
||||||
require.Equal(t, stackitem.Null{}, item)
|
require.Equal(t, stackitem.Null{}, item)
|
||||||
|
|
||||||
s.Set(1, stackitem.NewBigInteger(big.NewInt(42)), rc)
|
s.set(1, stackitem.NewBigInteger(big.NewInt(42)), rc)
|
||||||
require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1))
|
require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1))
|
||||||
require.Equal(t, 3, int(*rc))
|
require.Equal(t, 3, int(*rc))
|
||||||
}
|
}
|
||||||
|
|
20
pkg/vm/vm.go
20
pkg/vm/vm.go
|
@ -705,7 +705,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
sz := int(parameter[1])
|
sz := int(parameter[1])
|
||||||
ctx.arguments.init(sz, &v.refs)
|
ctx.arguments.init(sz, &v.refs)
|
||||||
for i := range sz {
|
for i := range sz {
|
||||||
ctx.arguments.Set(i, v.estack.Pop().Item(), &v.refs)
|
ctx.arguments.set(i, v.estack.Pop().Item(), &v.refs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,11 +719,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STSFLD0, opcode.STSFLD1, opcode.STSFLD2, opcode.STSFLD3, opcode.STSFLD4, opcode.STSFLD5, opcode.STSFLD6:
|
case opcode.STSFLD0, opcode.STSFLD1, opcode.STSFLD2, opcode.STSFLD3, opcode.STSFLD4, opcode.STSFLD5, opcode.STSFLD6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.sc.static.Set(int(op-opcode.STSFLD0), item, &v.refs)
|
ctx.sc.static.set(int(op-opcode.STSFLD0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STSFLD:
|
case opcode.STSFLD:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.sc.static.Set(int(parameter[0]), item, &v.refs)
|
ctx.sc.static.set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.LDLOC0, opcode.LDLOC1, opcode.LDLOC2, opcode.LDLOC3, opcode.LDLOC4, opcode.LDLOC5, opcode.LDLOC6:
|
case opcode.LDLOC0, opcode.LDLOC1, opcode.LDLOC2, opcode.LDLOC3, opcode.LDLOC4, opcode.LDLOC5, opcode.LDLOC6:
|
||||||
item := ctx.local.Get(int(op - opcode.LDLOC0))
|
item := ctx.local.Get(int(op - opcode.LDLOC0))
|
||||||
|
@ -735,11 +735,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STLOC0, opcode.STLOC1, opcode.STLOC2, opcode.STLOC3, opcode.STLOC4, opcode.STLOC5, opcode.STLOC6:
|
case opcode.STLOC0, opcode.STLOC1, opcode.STLOC2, opcode.STLOC3, opcode.STLOC4, opcode.STLOC5, opcode.STLOC6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.local.Set(int(op-opcode.STLOC0), item, &v.refs)
|
ctx.local.set(int(op-opcode.STLOC0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STLOC:
|
case opcode.STLOC:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.local.Set(int(parameter[0]), item, &v.refs)
|
ctx.local.set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.LDARG0, opcode.LDARG1, opcode.LDARG2, opcode.LDARG3, opcode.LDARG4, opcode.LDARG5, opcode.LDARG6:
|
case opcode.LDARG0, opcode.LDARG1, opcode.LDARG2, opcode.LDARG3, opcode.LDARG4, opcode.LDARG5, opcode.LDARG6:
|
||||||
item := ctx.arguments.Get(int(op - opcode.LDARG0))
|
item := ctx.arguments.Get(int(op - opcode.LDARG0))
|
||||||
|
@ -751,11 +751,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STARG0, opcode.STARG1, opcode.STARG2, opcode.STARG3, opcode.STARG4, opcode.STARG5, opcode.STARG6:
|
case opcode.STARG0, opcode.STARG1, opcode.STARG2, opcode.STARG3, opcode.STARG4, opcode.STARG5, opcode.STARG6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.arguments.Set(int(op-opcode.STARG0), item, &v.refs)
|
ctx.arguments.set(int(op-opcode.STARG0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STARG:
|
case opcode.STARG:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.arguments.Set(int(parameter[0]), item, &v.refs)
|
ctx.arguments.set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.NEWBUFFER:
|
case opcode.NEWBUFFER:
|
||||||
n := toInt(v.estack.Pop().BigInt())
|
n := toInt(v.estack.Pop().BigInt())
|
||||||
|
@ -1700,15 +1700,15 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
func (v *VM) unloadContext(ctx *Context) {
|
func (v *VM) unloadContext(ctx *Context) {
|
||||||
if ctx.local != nil {
|
if ctx.local != nil {
|
||||||
ctx.local.ClearRefs(&v.refs)
|
ctx.local.clearRefs(&v.refs)
|
||||||
}
|
}
|
||||||
if ctx.arguments != nil {
|
if ctx.arguments != nil {
|
||||||
ctx.arguments.ClearRefs(&v.refs)
|
ctx.arguments.clearRefs(&v.refs)
|
||||||
}
|
}
|
||||||
currCtx := v.Context()
|
currCtx := v.Context()
|
||||||
if currCtx == nil || ctx.sc != currCtx.sc {
|
if currCtx == nil || ctx.sc != currCtx.sc {
|
||||||
if ctx.sc.static != nil {
|
if ctx.sc.static != nil {
|
||||||
ctx.sc.static.ClearRefs(&v.refs)
|
ctx.sc.static.clearRefs(&v.refs)
|
||||||
}
|
}
|
||||||
if ctx.sc.onUnload != nil {
|
if ctx.sc.onUnload != nil {
|
||||||
err := ctx.sc.onUnload(v, ctx, v.uncaughtException == nil)
|
err := ctx.sc.onUnload(v, ctx, v.uncaughtException == nil)
|
||||||
|
|
Loading…
Reference in a new issue