neo-express
neo-express copied to clipboard
neo-trace fails to find contract that does exist
Describe the bug First apply the fix of #485 then run
neotrace transaction -r http://seed1.neo.org:10332 0xbc7f37a01dd94142f873068d32bf80302eab11a08ac872cb61ddb11924895592
fails with
Tracing transaction 0xbc7f37a01dd94142f873068d32bf80302eab11a08ac872cb61ddb11924895592 in block 7753996 (0xcd1f54fd5cd48e4af70814786a908807cda56f5591d667380d7d6fd0869ed71e)
Executing Transaction #0 (0x2facc946a30d45a73e5d1bf81ee6844a81507a1c860246f28da1ee195e11ffb1)
Executing Transaction #1 (0x3e141dace593af4a8c61ccbd676ae3a0ec280f881ccea4af7d8d4170b7634d98)
Executing Transaction #2 (0x852fced4b728773151192eea929e605c6e49bfdcad7b9ae826ba7e4986860bfa)
Unexpected script execution state. Expected HALT got FAULT reason: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.InvalidOperationException: Called Contract Does Not Exist: 0x341cbe084b3b15fccf15064c7b7790f5f0f659d2.mint
at Neo.SmartContract.ApplicationEngine.CallContract(UInt160 contractHash, String method, CallFlags callFlags, Array args) in /home/erik/code/neo-express/extras/neo/src/Neo/SmartContract/ApplicationEngine.Contract.cs:line 80
at InvokeStub_ApplicationEngine.CallContract(Object, Span`1)
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
--- End of inner exception stack trace ---
at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Neo.SmartContract.ApplicationEngine.OnSysCall(InteropDescriptor descriptor) in /home/erik/code/neo-express/extras/neo/src/Neo/SmartContract/ApplicationEngine.cs:line 644
at Neo.SmartContract.ApplicationEngine.OnSysCall(ExecutionEngine engine, Instruction instruction) in /home/erik/code/neo-express/extras/neo/src/Neo/SmartContract/ApplicationEngine.cs:line 268
at Neo.VM.ExecutionEngine.ExecuteNext() in /home/erik/code/neo-express/extras/neo/src/Neo.VM/ExecutionEngine.cs:line 149
Expected behavior I expect a trace to be created
Investigation and possible fix
The transactions that are traced will try to perform a contract call on the contract 0x341cbe084b3b15fccf15064c7b7790f5f0f659d2. This (as always) goes through the ContractManagement.GetContract() call, which queries the storage. That will eventually hit this
https://github.com/neo-project/neo-express/blob/d1326f742174b62650be48410caf3101ab44793b/src/bctklib/persistence/StateServiceStore.cs#L536-L540
DownloadStates() will create an entry for cached states. However, after committing the snapshot
https://github.com/neo-project/neo-express/blob/d1326f742174b62650be48410caf3101ab44793b/src/bctklib/persistence/StateServiceStore.cs#L599-L600
the list of states is cleared due to this line
https://github.com/neo-project/neo-express/blob/d1326f742174b62650be48410caf3101ab44793b/src/bctklib/persistence/StateServiceStore.MemoryCacheClient.cs#L120
and therefore by the time we hit TryGetCachedFoundStates() again, it contains no storages.
Commenting out that line resolves the issue. Whether it is the best approach I'm not sure.
The main problem is that Commit() stores the same instance of entries inside the concurrent dictionary. When Dispose executes entries.Clear(), it causes the list in the dictionary to be cleared. To fix it, I have created a copy of entries to store instead.
I executed a tx in an older block just to check that the problem is not related to Neo 3.8.2 but the issue is the same.
I'm researching the error in #487.
Thanks.