neo-express icon indicating copy to clipboard operation
neo-express copied to clipboard

neo-trace fails to find contract that does exist

Open ixje opened this issue 4 months ago • 1 comments

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.

ixje avatar Aug 04 '25 14:08 ixje

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.

ajara87 avatar Aug 12 '25 21:08 ajara87