Commit graph

64 commits

Author SHA1 Message Date
Roman Khimov
3eed9d06f8 stackitem: add some hint to 'seen' maps
It's empirical, we usually have one container, but four is likely to fit most
of regular cases.
2021-12-01 21:36:25 +03:00
Roman Khimov
d3198c3082 stackitem: avoid going through Value() in serialization
Doesn't change much, but still simpler.

name               old time/op    new time/op    delta
SerializeSimple-8     452ns ±10%     435ns ± 4%   ~     (p=0.356 n=10+9)

name               old alloc/op   new alloc/op   delta
SerializeSimple-8      432B ± 0%      432B ± 0%   ~     (all equal)

name               old allocs/op  new allocs/op  delta
SerializeSimple-8      7.00 ± 0%      7.00 ± 0%   ~     (all equal)
2021-08-23 18:29:07 +03:00
Evgeniy Stratonikov
6879f76a13 stackitem: make Buffer an alias to []byte
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-13 14:41:26 +03:00
Evgeniy Stratonikov
1dfef4ba26 stackitem: make ByteArray an alias to []byte
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-13 14:41:26 +03:00
Evgeniy Stratonikov
4f98ec2f53 vm: embed reference counter in compound items
```
name              old time/op  new time/op  delta
RefCounter_Add-8  44.8ns ± 4%  11.7ns ± 3%  -73.94%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-13 14:41:26 +03:00
Evgeniy Stratonikov
a5516e8c96 stackitem: make BigInteger alias to big.Int
Remove one indirection step.
``
name       old time/op    new time/op    delta
MakeInt-8    79.7ns ± 8%    56.2ns ± 8%  -29.44%  (p=0.000 n=10+10)

name       old alloc/op   new alloc/op   delta
MakeInt-8     48.0B ± 0%     40.0B ± 0%  -16.67%  (p=0.000 n=10+10)

name       old allocs/op  new allocs/op  delta
MakeInt-8      3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-12 17:53:36 +03:00
Evgeniy Stratonikov
cff8b1c24e stackitem: use Bool item directly
It is always copied.

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-12 17:53:36 +03:00
Evgeniy Stratonikov
f02d8b4ec4 stackitem: serialize integers to the pre-allocated slice
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-06 11:59:24 +03:00
Evgeniy Stratonikov
bdb9748c1b native/std: restrict amount of items in JSON deserialization
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-08-02 18:57:47 +03:00
Roman Khimov
19717dd9a8 slice: introduce common Copy helper
It's a bit more convenient to use.
2021-07-19 22:57:55 +03:00
Roman Khimov
1568ebc513 stackitem: rework struct cloning protection
Count everything, fail early, make it more compatible with
neo-project/neo-vm#423.
2021-07-19 15:42:42 +03:00
Roman Khimov
233307aca5 stackitem: completely drop MaxArraySize
Turns out C# VM doesn't have it since preview2, so our limiting of
MaxArraySize in incompatible with it. Removing this limit shouldn't be a
problem with the reference counter we have, both APPEND and SETITEM add things
to reference counter and we can't exceed MaxStackSize. PACK on the other hand
can't get more than MaxStackSize-1 of input elements.

Unify NEWSTRUCT with NEWARRAY* and use better integer checks at the same time.

Multisig limit is still 1024.
2021-07-19 15:42:42 +03:00
Roman Khimov
ee4a647934 stackitem: limit EQUAL for deeply nested structs
See neo-project/neo-vm#428.
2021-07-19 15:42:42 +03:00
Roman Khimov
f89f0300f6 stackitem: improve test coverage a bit 2021-07-19 15:42:42 +03:00
Roman Khimov
df2430d5e4 stackitem: limit deserialization to MaxDeserialized items
Follow neo-project/neo#2531. Even though it's not strictly required (our node
handles problematic script just fine) we better be compliant wrt
deserialization behavior. MaxDeserialized is introduced to avoid moving
MaxStackSize which is a VM parameter.
2021-07-19 15:42:42 +03:00
Roman Khimov
aab18c3083 stackitem: introduce Convertible interface
We have a lot of native contract types that are converted to stack items
before serialization, then deserialized as stack items and converted back to
regular structures. stackitem.Convertible allows to remove a lot of repetitive
io.Serializable code.

This also introduces to/from converter in testserdes which unfortunately
required to change util tests to avoid circular references.
2021-07-19 15:42:42 +03:00
Roman Khimov
fbe8bd2d9c stackitem: limit deserialized arrays/maps
See neo-project/neo#2531, even though they use MaxStackSize there resulting
element is not valid unless it has <=MaxArraySize elements.
2021-07-19 15:42:42 +03:00
Roman Khimov
654c4a6589 stackitem: properly pass allowInvalid on binary deserialization
Otherwise DecodeBinaryProtected() is broken for arrays/maps.
2021-07-19 15:42:41 +03:00
Roman Khimov
d638aee7a1
Merge pull request #2053 from nspcc-dev/stackitem-json
Speedup stackitem json serialization
2021-07-13 11:27:33 +03:00
Evgeniy Stratonikov
0611031fd4 stackitem/test: improve coverage for serialization
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-13 11:06:19 +03:00
Evgeniy Stratonikov
8fdc7e32f5 stackitem: cache serialized results in EncodeBinary
```
name            old time/op    new time/op    delta
EncodeBinary-8    8.39ms ± 1%    0.05ms ±21%  -99.44%  (p=0.000 n=10+9)

name            old alloc/op   new alloc/op   delta
EncodeBinary-8    2.24MB ± 0%    0.33MB ± 0%  -85.29%  (p=0.000 n=9+10)

name            old allocs/op  new allocs/op  delta
EncodeBinary-8     65.6k ± 0%      0.0k ± 0%  -99.95%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-13 11:06:19 +03:00
Evgeniy Stratonikov
17a3f17c74 stackitem: use byte-slice directly during encoding
```
name            old time/op    new time/op    delta
EncodeBinary-8    10.6ms ± 1%     8.4ms ± 1%  -20.94%  (p=0.000 n=9+10)

name            old alloc/op   new alloc/op   delta
EncodeBinary-8    1.64MB ± 0%    2.24MB ± 0%  +36.18%  (p=0.000 n=8+9)

name            old allocs/op  new allocs/op  delta
EncodeBinary-8      131k ± 0%       66k ± 0%  -49.98%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-13 11:06:18 +03:00
Evgeniy Stratonikov
c4eb7db8a5 stackitem: access value of Array/Struct directly
```
name      old time/op    new time/op    delta
ToJSON-8    50.3µs ±34%    47.8µs ± 9%     ~     (p=0.971 n=10+10)

name      old alloc/op   new alloc/op   delta
ToJSON-8     396kB ± 0%     396kB ± 0%   -0.10%  (p=0.000 n=6+10)

name      old allocs/op  new allocs/op  delta
ToJSON-8      34.0 ± 0%      18.0 ± 0%  -47.06%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-12 14:40:21 +03:00
Evgeniy Stratonikov
dc0a17dd0e stackitem: cache visited items while marshaling json
```
name      old time/op    new time/op    delta
ToJSON-8    4.52ms ± 4%    0.05ms ±34%  -98.89%  (p=0.000 n=8+10)

name      old alloc/op   new alloc/op   delta
ToJSON-8    2.13MB ± 0%    0.40MB ± 0%  -81.44%  (p=0.000 n=9+6)

name      old allocs/op  new allocs/op  delta
ToJSON-8     65.6k ± 0%      0.0k ± 0%  -99.95%  (p=0.000 n=10+10)
```

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-12 14:40:21 +03:00
Evgeniy Stratonikov
69cdd5252a stackitem: add benchmark for serialization routines
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-07-12 14:40:17 +03:00
Roman Khimov
cfe41abd35 vm: fix OOM during nested structure cloning
Resulting item can't have more than MaxStackSize elements. Technically this
limits to MaxStackSize cloned elements but it's considered to be enough to
mitigate the issue (the next size check is going to happen during push to the
stack). See neo-project/neo#2534, thanks @vang1ong7ang.
2021-07-11 18:47:50 +03:00
Roman Khimov
e62a766058 state: move nil check down to stackitem JSON processing
We want to return real errors, not some generic thing for any kind of thing
happening.
2021-07-07 00:38:19 +03:00
Roman Khimov
5a9efcc654 stackitem: rework error handling
Return good named errors everywhere, export appropriate constants, make
errors.Is() work.
2021-07-07 00:18:00 +03:00
Roman Khimov
0de949b575 stackitem: remove Item/StackItem from function names
They're useless in a package named 'stackitem', make this package a bit more
user-friendly.
2021-07-06 19:56:23 +03:00
Roman Khimov
b9ff07f32c stackitem: add limit to serialized items
Standard binary serialization/deserialization is mostly used in VM to put/get
elements into/from storage, so they never should exceed MaxSize (otherwise one
won't be able to deserialize these items).

This patch leaves EncodeBinaryStackItem unprotected, but that's a streaming
interface, so it's up to the user of it to ensure its appropriate use (and our
uses are mostly for native contract's data, so they're fine).
2021-07-06 19:34:02 +03:00
Roman Khimov
8472064bbc stackitem: refactor serialization code, add explicit context 2021-07-06 19:32:52 +03:00
Roman Khimov
1b7b7e4bec stackitem: don't overwrite error when serializing Item
We must get out as quickly as possible.
2021-07-06 17:51:46 +03:00
Roman Khimov
e34fa2e915 stackitem: limit JSONization nesting level
We can have very deep reference types and attempt to JSONize them can easily
lead to OOM (even though there are no recursive references inside). Therefore
we have to limit them. While regular ToJSON() is buffer size limited to
MaxSize, ToJSONWithTypes is not and limiting it to MaxSize output will require
substantial rewriting effort while not really providing fair result, MaxSize
is more about stack item size while its JSON representation can be much bigger
because of various overheads.

Initial thought was to limit it by element count based on
MaxIteratorResultItems, but the problem here is that we don't always have this
limit in contexts using ToJSONWithTypes (like notification event
marshaling). Thus we need some generic limit which would be fine for all
users.

We at the same time have maxJSONDepth used when deserializing from JSON, so
it can be used for marshaling as well, it's not often that we have deeper
structures in real results.

Inspired by neo-project/neo#2521.
2021-07-06 17:33:16 +03:00
Roman Khimov
6879cbcdcc stackitem: properly detect recursive references during serialization
If we're done with element it no longer can lead to recursion error, so fix
cases like `[arr, arr]` where we have two copies of `arr` trigger this error
for no good reason (there is no recursion there).
2021-07-06 17:10:31 +03:00
Evgeniy Stratonikov
8d67a03aec stackitem: fix Buffer deserialization
Fix incorrect application log for transaction in N3 testnet
8eb4076f1f1c07e693eda7e810779488a2d2b50aba9b727fd237cbc3adbec9e9

Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
2021-06-29 11:39:55 +03:00
Anna Shaleva
f95bdd9cb5 vm: serialize + rune as \u002B for byte-contained stackitems
This commit fixes the following Go vs C# state diff:

block 74613: value mismatch for key EwAAAHN0cmVhbXMvDg==: eyJpZCI6MTQsInN0YXJ0IjoxNjIyNTAwMjAwMDAwLCJzdG9wIjoxNjIyNTAyMDAwMDAwLCJkZXBvc2l0IjoxMDAwMDAwMDAsInJlbWFpbmluZyI6MTAwMDAwMDAwLCJzZW5kZXIiOiJmeEY4RDl2ZFU3K0gwcDV3NTlyWllMNytNSlE9IiwicmVjaXBpZW50IjoiSVV6c3pveFV0S1NGVnlZRGczSmdTQTFlbTFNPSJ9 vs eyJpZCI6MTQsInN0YXJ0IjoxNjIyNTAwMjAwMDAwLCJzdG9wIjoxNjIyNTAyMDAwMDAwLCJkZXBvc2l0IjoxMDAwMDAwMDAsInJlbWFpbmluZyI6MTAwMDAwMDAwLCJzZW5kZXIiOiJmeEY4RDl2ZFU3XHUwMDJCSDBwNXc1OXJaWUw3XHUwMDJCTUpRPSIsInJlY2lwaWVudCI6IklVenN6b3hVdEtTRlZ5WURnM0pnU0ExZW0xTT0ifQ==

I.e.:
```
{"id":14,"start":1622500200000,"stop":1622502000000,"deposit":100000000,"remaining":100000000,"sender":"fxF8D9vdU7+H0p5w59rZYL7+MJQ=","recipient":"IUzszoxUtKSFVyYDg3JgSA1em1M="}
```
vs
```
{"id":14,"start":1622500200000,"stop":1622502000000,"deposit":100000000,"remaining":100000000,"sender":"fxF8D9vdU7\u002BH0p5w59rZYL7\u002BMJQ=","recipient":"IUzszoxUtKSFVyYDg3JgSA1em1M="}
```
2021-06-08 16:40:38 +03:00
Roman Khimov
9d2712573f *: enable godot linter and fix all its warnings
It's important for NeoGo to have clean documentation. No functional changes.
2021-05-12 23:17:03 +03:00
Evgeniy Stratonikov
e5fbf04529 stackitem: escape control characters in ToJSON()
Decoding uses `json.Decoder` which handles everything for us.
2021-03-02 10:47:02 +03:00
Evgenii Stratonikov
8c22d27acc state: allow to encode AppExecResult with recursive items
1. Encode them to a special type, decode to `nil`.
2. `Interop` can be encoded in JSON, this info should also be preserved.
2020-12-18 13:04:31 +03:00
Evgenii Stratonikov
18b331d765 stackitem: fix JSON encoding
Encode both `Buffer` and `ByteString` to UTF-8 bytes.
Follow https://github.com/neo-project/neo/pull/1715 .
2020-12-11 13:30:47 +03:00
Roman Khimov
0120a8f239 stackitem: limit buffer/bytearray reads upon deserialization
This is not the way it's done in C#, but that's the most sensible approach to
me.
2020-10-07 23:08:20 +03:00
Roman Khimov
64e9775707 vm/stackitem: limit reads for bigint values
They can't exceed 33 bytes.
2020-10-07 23:07:10 +03:00
Evgenii Stratonikov
96bca91e4b vm: handle very big int creation properly
Determine size as in reference implementation instead of
`big.Int.BitLen()`

Close #1437.
2020-10-07 11:50:42 +03:00
Anna Shaleva
543fd58e93 vm: restrict map key size 2020-09-29 18:46:15 +03:00
Anna Shaleva
1f9b92c295 vm: restrict comparable ByteArray length
MaxByteArrayComparableSize should equals to 65535.
2020-09-29 10:42:01 +03:00
Roman Khimov
324f4c265b stackitem: don't copy existing slices for TryBytes
Most often we only need to read them and it doesn't require copying. Make an
explicit copy (and copy only things we need!) where needed.

After the recent neo-vm tests update our vm package testing time jumped to
~12s, with this change it's now more like ~8s.
2020-08-22 23:36:38 +03:00
Roman Khimov
74097ae8b0 stackitem: add NewPointerWithHash() to save on hash calculations
Inspired by neo-project/neo-vm#352. We can't directly compare slices, so we're
better optimize things we already have. At the same time this code would
behave a bit different if A is to call B and then B is call A and then some
pointer from the first A invocation is to be compared with a pointer from the
second A invocation. Not sure it really matters.
2020-08-22 22:19:44 +03:00
Roman Khimov
93f51f922a stackitem: return error in TryBytes() for big byte strings
Follow neo-project/neo-vm#349.
2020-08-21 21:05:47 +03:00
Roman Khimov
a7670303e8 stackitem: change Bool() to TryBool(), prepare for its failures 2020-08-21 20:55:20 +03:00
Evgenii Stratonikov
b8cc33d0b2 stackitem: implement DeepCopy 2020-08-05 11:19:41 +03:00