forked from neo-project/neo-devpack-dotnet
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathEntryPoint.cs
88 lines (82 loc) · 3.25 KB
/
EntryPoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using Neo.Json;
using Neo.SmartContract;
using Neo.SmartContract.Manifest;
using Neo.VM;
using System.Collections.Generic;
using System.Linq;
namespace Neo.Optimizer
{
public enum EntryType
{
PublicMethod,
Initialize,
PUSHA,
}
public static class EntryPoint
{
/// <summary>
///
/// </summary>
/// <param name="nef"></param>
/// <param name="manifest"></param>
/// <param name="debugInfo"></param>
/// <returns>(addr -> EntryType, hasCallA)</returns>
public static Dictionary<int, EntryType> EntryPointsByMethod(ContractManifest manifest, JToken debugInfo)
{
Dictionary<int, EntryType> result = new();
foreach (ContractMethodDescriptor method in manifest.Abi.Methods)
{
if (method.Name == "_initialize")
result.Add(method.Offset, EntryType.Initialize);
else
result.Add(method.Offset, EntryType.PublicMethod);
}
foreach (JToken? method in (JArray)debugInfo["methods"]!)
{
string name = method!["name"]!.AsString(); // NFTLoan.NFTLoan,RegisterRental
name = name[(name.LastIndexOf(',') + 1)..]; // RegisterRental
name = char.ToLower(name[0]) + name[1..]; // registerRental
if (name == "_deploy")
{
int startAddr = int.Parse(method!["range"]!.AsString().Split("-")[0]);
result[startAddr] = EntryType.Initialize; // set instead of add; _deploy may be in the manifest
}
}
return result;
}
public static Dictionary<int, EntryType> EntryPointsByCallA(NefFile nef)
{
Dictionary<int, EntryType> result = new();
Script script = nef.Script;
List<(int, Instruction)> instructions = script.EnumerateInstructions().ToList();
bool hasCallA = HasCallA(instructions);
if (hasCallA)
foreach ((int addr, Instruction instruction) in instructions)
if (instruction.OpCode == OpCode.PUSHA)
{
int target = JumpTarget.ComputeJumpTarget(addr, instruction);
if (target != addr && target >= 0)
result.Add(addr, EntryType.PUSHA);
}
return result;
}
public static bool HasCallA(List<(int, Instruction)> instructions)
{
bool hasCallA = false;
foreach ((_, Instruction instruction) in instructions)
if (instruction.OpCode == OpCode.CALLA)
{
hasCallA = true;
break;
}
return hasCallA;
}
public static bool HasCallA(NefFile nef)
{
Script script = nef.Script;
return HasCallA(script.EnumerateInstructions().ToList());
}
public static Dictionary<int, EntryType> AllEntryPoints(NefFile nef, ContractManifest manifest, JToken debugInfo)
=> EntryPointsByCallA(nef).Concat(EntryPointsByMethod(manifest, debugInfo)).ToDictionary(kv => kv.Key, kv => kv.Value);
}
}