VM always has istack and it doesn't even change, so doing this microallocation
makes no sense. Notice that estack is a bit harder to change we do replace it
in some cases and we compare pointers to it as well.
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.
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.
We already do this in binary opcodes, let's be consistent.
This fixes state difference at height 275663
for tx 3c498317684d63849b03e4c58ad57ce4b19bb206b7b01bcc64233de3b3e207f4
Signed-off-by: Evgeniy Stratonikov <evgeniy@nspcc.ru>
The result is the same HALT state, but the exception message is the real
one got from user. Changes ported from C#:
1. Throw exception: 59b8ac73d2/src/neo-vm/ExecutionEngine.cs (L1448)
2. Prettify message: https://github.com/neo-project/neo-vm/blob/master/src/neo-vm/VMUnhandledException.cs#L28
The result is that instead of
```
2021-03-31T17:02:54.508+0300 WARN contract invocation failed {"tx": "2aefeb705f3a609df8767d9b45e036b9dd1eb77407e5732375981915668889b8", "block": 30640, "error": "error encountered at instruction 970 (THROW): runtime error: invalid memory address or nil pointer dereference"}
```
we'll get
```
2021-03-31T17:33:56.299+0300 WARN contract invocation failed {"tx": "2aefeb705f3a609df8767d9b45e036b9dd1eb77407e5732375981915668889b8", "block": 30640, "error": "error encountered at instruction 970 (THROW): unhandled exception: No authorization."}
```
in the node logs.
We have additional logic for getting BaseExecFee policy value. This
logic should be moved to interop context instead of being in Policer,
because Policer is just an interface over Policy contract.
After moving this logic to interop context, we need to use it to define
BaseExecFee instead of (Policer).BaseExecFee. Thus, moving
(*Blockchain).GetPrice to (*Context).GetPrice is necessary.
This optimizes out DB access for non-deployed contracts under the assumption
that deployed ones are always loaded via `LoadScriptWithHash` (and if they're
not --- it's a bug anyway with the new hashing model) which actually is a very
popular case (every entry script does that).
At the moment we should have 3 possible options to check return state
during vm context unloading:
* no check
* ensure the stack is empty
* ensure the stack is not empty
It is necessary to distinguish them because new _deploy method shouldn't
left anything on stack. Example: if we use _deploy method before some
ordinary contract method which returns one value. Without these changes
the contract invocation will fail due to 2 elements on stack left after
invocation (the first `null` element is from _deploy, the second element
is return-value from the ordinary contract method).
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.
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.
1. `Run()` must be able to continue execution after a breakpoint.
2. VM must stop right before the breakpoint, not after.
3. Initial vm state is NONE, not HALT.
When calling external contracts we expect exactly 1 value to be on
stack. For methods returning nothing, `Null` value is pushed, otherwise
it is an error.`
It's not needed any more with Go 1.13 as we have wrapping/unwrapping in base
packages. All errors.Wrap calls are replaced with fmt.Errorf, some strings are
improved along the way.
Allow to invoke methods by offset:
1. Every invoked contract must have manifest.
2. Check arguments count on invocation.
3. Change AppCall to a regular syscall.
4. Add test suite for `System.Contract.Call`.
Implement 3 new instructions: TRY,ENDTRY,ENDFINALLY.
1. TRY marks the start of the block where exceptions are catched.
It has 2 arguments which are relative offsets of exception handler
and the end of the whole try/catch construction.
2. ENDTRY denotes either end of try or catch block.
3. ENDFINALLY denotes end of finally block which is executed
irregardless of whether an exception has occured.
We were accepting transactions with zero system fee, but we shouldn't do
that. Also, transaction's verification execution has to be limited by network
fee.
Regular CALLs don't update it, only Contract.Call does. Fixes the following
mismatch on preview2 testnet:
file BlockStorage_100000/dump-block-49000.json: block 48644, changes number mismatch: 6 vs 4