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

GetInvocationCounter #813

Merged
merged 12 commits into from
Jun 13, 2019
63 changes: 63 additions & 0 deletions neo.UnitTests/UT_Syscalls.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.Ledger;
using Neo.SmartContract;
using Neo.VM;
using System.Linq;

namespace Neo.UnitTests
{
[TestClass]
public class UT_Syscalls
{
[TestMethod]
public void System_Runtime_GetInvocationCounter()
{
var snapshot = TestBlockchain.GetStore().GetSnapshot();
var contracts = (TestDataCache<UInt160, ContractState>)snapshot.Contracts;

// Call System.Runtime.GetInvocationCounter syscall

var script = new ScriptBuilder();
script.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter);

// Init A,B,C contracts
// First two drops is for drop method and arguments

var contractA = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script.ToArray()).ToArray() };
var contractB = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };
var contractC = new ContractState() { Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP, (byte)OpCode.NOP, (byte)OpCode.NOP }.Concat(script.ToArray()).ToArray() };

contracts.Add(contractA.ScriptHash, contractA);
contracts.Add(contractB.ScriptHash, contractB);
contracts.Add(contractC.ScriptHash, contractC);

// Call A,A,B,C

script = new ScriptBuilder();
script.EmitSysCall(InteropService.System_Contract_Call, contractA.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractA.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractB.ScriptHash.ToArray(), "dummyMain", 0);
script.EmitSysCall(InteropService.System_Contract_Call, contractC.ScriptHash.ToArray(), "dummyMain", 0);

// Execute

var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true);
engine.LoadScript(script.ToArray());
Assert.AreEqual(engine.Execute(), VMState.HALT);

// Check the results

CollectionAssert.AreEqual
(
engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(),
new int[]
{
1, /* C */
2, /* B */
1, /* A */
erikzhang marked this conversation as resolved.
Show resolved Hide resolved
1 /* A */
}
);
}
}
}
1 change: 1 addition & 0 deletions neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public partial class ApplicationEngine : ExecutionEngine
private readonly List<NotifyEventArgs> notifications = new List<NotifyEventArgs>();
private readonly List<IDisposable> disposables = new List<IDisposable>();

public Dictionary<UInt160, int> InvocationCounter { get; } = new Dictionary<UInt160, int>();
shargon marked this conversation as resolved.
Show resolved Hide resolved
public TriggerType Trigger { get; }
public IVerifiable ScriptContainer { get; }
public Snapshot Snapshot { get; }
Expand Down
21 changes: 21 additions & 0 deletions neo/SmartContract/InteropService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public static partial class InteropService
public static readonly uint System_Runtime_GetTime = Register("System.Runtime.GetTime", Runtime_GetTime, 0_00000250);
public static readonly uint System_Runtime_Serialize = Register("System.Runtime.Serialize", Runtime_Serialize, 0_00100000);
public static readonly uint System_Runtime_Deserialize = Register("System.Runtime.Deserialize", Runtime_Deserialize, 0_00500000);
public static readonly uint System_Runtime_GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", Runtime_GetInvocationCounter, 10000/*TODO Compute Gas*/);
shargon marked this conversation as resolved.
Show resolved Hide resolved
public static readonly uint System_Crypto_Verify = Register("System.Crypto.Verify", Crypto_Verify, 0_01000000);
public static readonly uint System_Blockchain_GetHeight = Register("System.Blockchain.GetHeight", Blockchain_GetHeight, 0_00000400);
public static readonly uint System_Blockchain_GetHeader = Register("System.Blockchain.GetHeader", Blockchain_GetHeader, 0_00007000);
Expand Down Expand Up @@ -212,6 +213,17 @@ private static bool Runtime_Serialize(ApplicationEngine engine)
return true;
}

private static bool Runtime_GetInvocationCounter(ApplicationEngine engine)
{
if (!engine.InvocationCounter.TryGetValue(engine.CurrentScriptHash, out var counter))
{
counter = 1;
shargon marked this conversation as resolved.
Show resolved Hide resolved
}

engine.CurrentContext.EvaluationStack.Push(counter);
return true;
}

private static bool Runtime_Deserialize(ApplicationEngine engine)
{
StackItem item;
Expand Down Expand Up @@ -499,6 +511,15 @@ private static bool Contract_Call(ApplicationEngine engine)
if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method.GetString()))
return false;

if (engine.InvocationCounter.TryGetValue(contract.ScriptHash, out var counter))
{
engine.InvocationCounter[contract.ScriptHash] = counter + 1;
}
else
{
engine.InvocationCounter[contract.ScriptHash] = 1;
Copy link
Member

Choose a reason for hiding this comment

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

Shargon, could this Dictionary be already initialized in 1 and avoid this if?

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 need to increment the value, so you need to query the previous value

Copy link
Member

Choose a reason for hiding this comment

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

Yes, but I mean, for the first time initialize already with 1 and then just increment.

Copy link
Member

Choose a reason for hiding this comment

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

This would simplify the if.

Copy link
Member Author

@shargon shargon Jun 12, 2019

Choose a reason for hiding this comment

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

It's initialized to 1 when it is not found

}

ExecutionContext context_new = engine.LoadScript(contract.Script, 1);
context_new.EvaluationStack.Push(args);
context_new.EvaluationStack.Push(method);
Expand Down