Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add diagnostic for ApplicationEngine #2613

Merged
merged 7 commits into from
Nov 10, 2021
Merged

Add diagnostic for ApplicationEngine #2613

merged 7 commits into from
Nov 10, 2021

Conversation

erikzhang
Copy link
Member

No description provided.

Copy link
Member

@shargon shargon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add the callwed syscalls?

@@ -250,6 +259,8 @@ internal ContractTask<T> CallFromNativeContract<T>(UInt160 callingScriptHash, UI
protected override void ContextUnloaded(ExecutionContext context)
{
base.ContextUnloaded(context);
if (Diagnostic is not null)
currentNodeOfInvocationTree = currentNodeOfInvocationTree.Parent;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the parent of currentNodeOfInvocationTree is null? should we also remove the root of Diagnostic?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't matter.


namespace Neo.SmartContract
{
public class Diagnostic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic seems like a poor name for this class. It sounds to me as if it is more general purpose than simply tracking the tree of contract invocations. Could we call the class InvocationTree and call the property Contracts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can add more functions to Diagnostic later.

/// <returns>The engine instance created.</returns>
public static ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas)
public static ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas, Diagnostic diagnostic = null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic parameter should have null default value to avoid code breakage

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does have a null default value.

@@ -28,7 +28,8 @@ public interface IApplicationEngineProvider
/// <param name="persistingBlock">The block being persisted. It should be <see langword="null"/> if the <paramref name="trigger"/> is <see cref="TriggerType.Verification"/>.</param>
/// <param name="settings">The <see cref="ProtocolSettings"/> used by the engine.</param>
/// <param name="gas">The maximum gas used in this execution. The execution will fail when the gas is exhausted.</param>
/// <param name="diagnostic">The diagnostic to be used by the <see cref="ApplicationEngine"/>.</param>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diagnostic parameter should have null default value to avoid code breakage

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interface. I think it is meaningless to add the default parameter. Because all classes that implement this interface should be updated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there's a null default value, we also have to update code that calls into classes that implement this interface.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The classes are not to be called directly. We need to use ApplicationEngine.Create() instead.

var state = context.GetState<ExecutionContextState>();
state.ScriptHash ??= ((byte[])context.Script).ToScriptHash();
invocationCounter.TryAdd(state.ScriptHash, 1);

if (Diagnostic is not null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an interesting problem related to #2130 (comment), suppose we have a deployed contract with onNEP17Payment, we transfer some NEO to it, add a number of blocks and then transfer 1 NEO more. This triggers GAS distribution and onNEP17Payment call from GAS contract (even before onNEP17Payment call from NEO). The contract can ask GetCallingScriptHash() and get GAS hash in return, because this invocation is made from the GAS contract. But this will never be reflected in the invocation tree, there we'll have

  • entry
    • NEO
      • contract
      • contract

instead of

  • entry
    • NEO
      • GAS
        • contract
      • contract

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants