[#931] morph: Provide batch size for container listing explicitly
All checks were successful
DCO action / DCO (pull_request) Successful in 10m57s
Vulncheck / Vulncheck (pull_request) Successful in 12m22s
Build / Build Components (1.20) (pull_request) Successful in 13m53s
Build / Build Components (1.21) (pull_request) Successful in 13m49s
Tests and linters / Staticcheck (pull_request) Successful in 15m4s
Tests and linters / Lint (pull_request) Successful in 20m4s
Tests and linters / Tests (1.21) (pull_request) Successful in 2m19s
Tests and linters / Tests with -race (pull_request) Successful in 3m51s
Tests and linters / Tests (1.20) (pull_request) Successful in 15m44s

Besides VM stack item limit we also have restrictions on the size of
JSON for a stackitem, which is 128k. This limit is much harder to
calculate, because JSON representation includes type and the encoding is
different for different items. Thus is makes no sense to invent our own
default, so use the one provided by neo-go. But for container listing we
know exactly what we process, so use big enough value, which is tested.

Introduced in be8607a1f6.

Refs #902
Refs https://github.com/nspcc-dev/neo-go/blob/v0.105.0/pkg/vm/stackitem/json.go#L353

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
Evgenii Stratonikov 2024-01-25 11:21:00 +03:00
parent cc2da73b20
commit 7502b9f07a
2 changed files with 13 additions and 9 deletions

View file

@ -22,13 +22,13 @@ import (
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/rolemgmt"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
"github.com/nspcc-dev/neo-go/pkg/wallet"
@ -207,16 +207,11 @@ func (c *Client) Invoke(contract util.Uint160, fee fixedn.Fixed8, method string,
return vub, nil
}
// defaultPrefetchBatchSize is the default number of items to prefetch.
// It is dependent on VM limits (2048 items on stack), the default works for simple items.
// For example, to iterate over 2 field structs, the limit should be divided by 3 = 1 (struct itself) + 2 (fields).
const defaultPrefetchBatchSize = vm.MaxStackSize - 16
// TestInvokeIterator invokes contract method returning an iterator and executes cb on each element.
// If cb returns an error, the session is closed and this error is returned as-is.
// If the remove neo-go node does not support sessions, `unwrap.ErrNoSessionID` is returned.
// batchSize is the number of items to prefetch: if the number of items in the iterator is less than batchSize, no session will be created.
// The default batchSize is 2000 (VM is limited by having 2048 items on stack, so if each iterator item is simple, 2000 items won't hit the limit).
// The default batchSize is 100, the default limit from neo-go.
func (c *Client) TestInvokeIterator(cb func(stackitem.Item) error, batchSize int, contract util.Uint160, method string, args ...interface{}) error {
start := time.Now()
success := false
@ -225,7 +220,7 @@ func (c *Client) TestInvokeIterator(cb func(stackitem.Item) error, batchSize int
}()
if batchSize <= 0 {
batchSize = defaultPrefetchBatchSize
batchSize = invoker.DefaultIteratorResultItems
}
c.switchLock.RLock()

View file

@ -40,8 +40,17 @@ func (c *Client) ContainersOf(idUser *user.ID) ([]cid.ID, error) {
return nil
}
// We would like to have batch size as big as possible,
// to reduce the number of round-trips and avoid creating sessions.
// The limit depends on 2 things:
// 1. VM limits: max 2048 items on stack.
// 2. JSON encoded size for the item with type = 128k.
// It turns out, that for container ID the second limit is hit first,
// 512 is big enough value and it is beautiful.
const batchSize = 512
cnrHash := c.client.ContractAddress()
err := c.client.Morph().TestInvokeIterator(cb, 0, cnrHash, containersOfMethod, rawID)
err := c.client.Morph().TestInvokeIterator(cb, batchSize, cnrHash, containersOfMethod, rawID)
if err != nil {
if errors.Is(err, unwrap.ErrNoSessionID) {
return c.List(idUser)