Skip to content

Commit f71de42

Browse files
Hecate2shargon
authored andcommitted
Refator: Entry point analyser (neo-project#971)
* Add directory `Analysers` * entry point analyser --------- Co-authored-by: Shargon <shargon@gmail.com>
1 parent 4397e33 commit f71de42

File tree

4 files changed

+90
-18
lines changed

4 files changed

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

src/Neo.Compiler.CSharp/Optimizer/Strategies/Reachability.cs

+2-18
Original file line numberDiff line numberDiff line change
@@ -167,28 +167,12 @@ public static Dictionary<int, BranchType>
167167
foreach ((int addr, Instruction _) in script.EnumerateInstructions())
168168
coveredMap.Add(addr, BranchType.UNCOVERED);
169169

170-
Dictionary<int, string> publicMethodStartingAddressToName = new();
171-
foreach (ContractMethodDescriptor method in manifest.Abi.Methods)
172-
publicMethodStartingAddressToName.Add(method.Offset, method.Name);
173-
174170
// It is unsafe to go parallel, because the coveredMap value is not true/false
175171
//Parallel.ForEach(manifest.Abi.Methods, method =>
176172
// CoverInstruction(method.Offset, script, coveredMap)
177173
//);
178-
foreach (ContractMethodDescriptor method in manifest.Abi.Methods)
179-
CoverInstruction(method.Offset, script, coveredMap);
180-
// start from _deploy method
181-
foreach (JToken? method in (JArray)debugInfo["methods"]!)
182-
{
183-
string name = method!["name"]!.AsString(); // NFTLoan.NFTLoan,RegisterRental
184-
name = name[(name.LastIndexOf(',') + 1)..]; // RegisterRental
185-
name = char.ToLower(name[0]) + name[1..]; // registerRental
186-
if (name == "_deploy")
187-
{
188-
int startAddr = int.Parse(method!["range"]!.AsString().Split("-")[0]);
189-
CoverInstruction(startAddr, script, coveredMap);
190-
}
191-
}
174+
foreach ((int addr, _) in EntryPoint.EntryPointsByMethod(manifest, debugInfo))
175+
CoverInstruction(addr, script, coveredMap);
192176
return coveredMap;
193177
}
194178

0 commit comments

Comments
 (0)