mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 09:29:38 +00:00
Merge pull request #3485 from nspcc-dev/test-maxstacksize
This commit is contained in:
commit
02627e948f
3 changed files with 83 additions and 2 deletions
|
@ -2620,3 +2620,78 @@ func TestBlockchain_StoreAsTransaction_ExecutableConflict(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 2, len(aer))
|
require.Equal(t, 2, len(aer))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestEngineLimits ensures that MaxStackSize limit is preserved during System.Runtime.GetNotifications
|
||||||
|
// syscall handling. This test is an adjusted port of https://github.com/lazynode/Tanya/pull/33 and makes
|
||||||
|
// sure that NeoGo node is not affected by https://github.com/neo-project/neo/issues/3300 and does not need
|
||||||
|
// the https://github.com/neo-project/neo/pull/3301.
|
||||||
|
func TestEngineLimits(t *testing.T) {
|
||||||
|
bc, acc := chain.NewSingle(t)
|
||||||
|
e := neotest.NewExecutor(t, bc, acc, acc)
|
||||||
|
|
||||||
|
src := `package test
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||||
|
)
|
||||||
|
// args is an array of LargeEvent parameters containing 500 empty strings.
|
||||||
|
var args = []any{"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
|
||||||
|
func ProduceNumerousNotifications(count int) [][]any {
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
runtime.Notify("LargeEvent", args...)
|
||||||
|
}
|
||||||
|
return runtime.GetNotifications(runtime.GetExecutingScriptHash())
|
||||||
|
}
|
||||||
|
func ProduceLargeObject(count int) int {
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
runtime.Notify("LargeEvent", args...)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
smallObject = make([]int, 100)
|
||||||
|
res []int
|
||||||
|
)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
runtime.GetNotifications(runtime.GetExecutingScriptHash())
|
||||||
|
res = append(res, smallObject...)
|
||||||
|
}
|
||||||
|
return len(res)
|
||||||
|
}`
|
||||||
|
const eArgsCount = 500
|
||||||
|
eParams := make([]compiler.HybridParameter, eArgsCount)
|
||||||
|
for i := range eParams {
|
||||||
|
eParams[i].Name = fmt.Sprintf("str%d", i)
|
||||||
|
eParams[i].Type = smartcontract.ByteArrayType
|
||||||
|
}
|
||||||
|
c := neotest.CompileSource(t, acc.ScriptHash(), strings.NewReader(src), &compiler.Options{
|
||||||
|
Name: "test_contract",
|
||||||
|
ContractEvents: []compiler.HybridEvent{
|
||||||
|
{
|
||||||
|
Name: "LargeEvent",
|
||||||
|
Parameters: eParams,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
e.DeployContract(t, c, nil)
|
||||||
|
|
||||||
|
// ProduceNumerousNotifications: 1 iteration, no limits are hit.
|
||||||
|
var args = make([]stackitem.Item, eArgsCount)
|
||||||
|
for i := range args {
|
||||||
|
args[i] = stackitem.Make("")
|
||||||
|
}
|
||||||
|
cInv := e.NewInvoker(c.Hash, acc)
|
||||||
|
cInv.Invoke(t, stackitem.Make([]stackitem.Item{
|
||||||
|
stackitem.Make([]stackitem.Item{
|
||||||
|
stackitem.Make(c.Hash),
|
||||||
|
stackitem.Make("LargeEvent"),
|
||||||
|
stackitem.Make(args),
|
||||||
|
}),
|
||||||
|
}), "produceNumerousNotifications", 1)
|
||||||
|
|
||||||
|
// ProduceNumerousNotifications: hit the limit.
|
||||||
|
cInv.InvokeFail(t, "stack is too big", "produceNumerousNotifications", 500)
|
||||||
|
|
||||||
|
// ProduceLargeObject: 1 iteration, no limits are hit.
|
||||||
|
cInv.Invoke(t, 100*1, "produceLargeObject", 1)
|
||||||
|
|
||||||
|
// ProduceLargeObject: hit the limit.
|
||||||
|
cInv.InvokeFail(t, "stack is too big", "produceLargeObject", 500)
|
||||||
|
}
|
||||||
|
|
|
@ -128,6 +128,12 @@ func Make(v any) Item {
|
||||||
a = append(a, Make(i))
|
a = append(a, Make(i))
|
||||||
}
|
}
|
||||||
return Make(a)
|
return Make(a)
|
||||||
|
case []string:
|
||||||
|
var a []Item
|
||||||
|
for _, i := range val {
|
||||||
|
a = append(a, Make(i))
|
||||||
|
}
|
||||||
|
return Make(a)
|
||||||
case []any:
|
case []any:
|
||||||
res := make([]Item, len(val))
|
res := make([]Item, len(val))
|
||||||
for i := range val {
|
for i := range val {
|
||||||
|
|
|
@ -594,7 +594,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
err = newError(ctx.ip, op, errRecover)
|
err = newError(ctx.ip, op, errRecover)
|
||||||
} else if v.refs > MaxStackSize {
|
} else if v.refs > MaxStackSize {
|
||||||
v.state = vmstate.Fault
|
v.state = vmstate.Fault
|
||||||
err = newError(ctx.ip, op, "stack is too big")
|
err = newError(ctx.ip, op, fmt.Sprintf("stack is too big: %d vs %d", int(v.refs), MaxStackSize))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -1995,7 +1995,7 @@ func validateMapKey(key Element) {
|
||||||
|
|
||||||
func (v *VM) checkInvocationStackSize() {
|
func (v *VM) checkInvocationStackSize() {
|
||||||
if len(v.istack) >= MaxInvocationStackSize {
|
if len(v.istack) >= MaxInvocationStackSize {
|
||||||
panic("invocation stack is too big")
|
panic(fmt.Sprintf("invocation stack is too big: %d", len(v.istack)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue