Skip to content

Commit

Permalink
GetInvocationCounter (#813)
Browse files Browse the repository at this point in the history
* GetInvocationCounter

* UT as sample

* Fix travis

* Update neo/SmartContract/InteropService.cs

* Update neo/SmartContract/ApplicationEngine.cs

Co-Authored-By: Erik Zhang <[email protected]>

* Update neo/SmartContract/InteropService.cs

Co-Authored-By: Erik Zhang <[email protected]>

* We need Writable dictionary

* internal
  • Loading branch information
shargon authored Jun 13, 2019
1 parent 354563d commit fe3ab04
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 0 deletions.
64 changes: 64 additions & 0 deletions neo.UnitTests/UT_Syscalls.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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.DeleteWhere((a, b) => true);
contracts.Add(contractA.ScriptHash, contractA);
contracts.Add(contractB.ScriptHash, contractB);
contracts.Add(contractC.ScriptHash, contractC);

// Call A,B,B,C

script = new ScriptBuilder();
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, 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, /* A */
1, /* B */
2, /* B */
1 /* C */
}
);
}
}
}
1 change: 1 addition & 0 deletions neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public partial class ApplicationEngine : ExecutionEngine
public UInt160 CallingScriptHash => hashes.Count > 1 ? hashes.Peek(1) : null;
public UInt160 EntryScriptHash => hashes.Count > 0 ? hashes.Peek(hashes.Count - 1) : null;
public IReadOnlyList<NotifyEventArgs> Notifications => notifications;
internal Dictionary<UInt160, int> InvocationCounter { get; } = new Dictionary<UInt160, int>();

public ApplicationEngine(TriggerType trigger, IVerifiable container, Snapshot snapshot, long gas, bool testMode = false)
{
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, 0_00000400);
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))
{
return false;
}

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;
}

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

0 comments on commit fe3ab04

Please sign in to comment.