VM: do not pop too many items from stack
JSON tests in neo-vm check stack state even in case of failure.
There are 2 corrections need to be done:
Pop items in EQUAL one-by-one.
Do not pop anything from stack in OVER.
I have also implemented operand restriction for SHL/SHR.
It must copy both the value and the key because they can be reused for other
purposes between Put() and PutBatch(). This actually happens with values in
headers processing, leading to wrong data being written into the DB.
Extend the batch test to check for that.
For example, at the moment our node can't handle `consensus` message, so when
it received it before the patch it just crashed because of uninitialized `p`.
earlier we had an issue with failing test in #353 and other one #305.
Reworked these test to have in-memory database. This led to multiple
changes: made some functions like Hash and Persist public(otherwise
it's not possible to control state of the blockchain); removed
unit_tests storage package which was used mainly for leveldb in unit
tests.
I see these tests not really good since they look like e2e tests and
as for me should be run in separate step against dockerized env or
in case we want to check rpc handler we might want to rework it in order
to have interface for proper unit tests.
As for me this patchset at least makes as safe with not removing totally
previous tests and at the same time CircleCI will be happy now.
Move BinReader/BinWriter to io and simplify things
BinReader and BinWriter don't belong to util, actually util shouldn't
exist at all. Moving them to io and using them for all encoding/decoding
purposes allows to simplify a lot of code, especially in the error
handling space. These interfaces are designed to absorb errors until
someone can do something meaningful with them (usually that's the top
caller of encode/decode functions) and our current use of them is
inconsistent.
This patchset moves BinReader/BinWriter and size calculations (that
are mostly about Serializable things) to io package and makes all the
other code use them for encoding/decoding purposes.
It's mostly used for Serializable and in other cases where one needs to
estimate binary-encoded size of the stucture. This also simplifies future
removal of the Size() from Serializable.