mirror of
https://gitee.com/BDWare/cp.git
synced 2025-06-12 10:44:02 +00:00
1455 lines
59 KiB
Java
1455 lines
59 KiB
Java
package org.bdware.sc;
|
||
|
||
import com.google.gson.*;
|
||
import com.google.gson.reflect.TypeToken;
|
||
import com.google.gson.stream.MalformedJsonException;
|
||
import org.apache.logging.log4j.Level;
|
||
import org.apache.logging.log4j.core.config.Configurator;
|
||
import org.bdware.analysis.BasicBlock;
|
||
import org.bdware.analysis.CFGraph;
|
||
import org.bdware.analysis.FrontCF;
|
||
import org.bdware.analysis.dynamic.NaiveDynamicTaintAnalysis;
|
||
import org.bdware.analysis.dynamic.TracedFile;
|
||
import org.bdware.analysis.example.MultiSourceTaintAnalysis;
|
||
import org.bdware.analysis.gas.Evaluates;
|
||
import org.bdware.analysis.gas.PPCount;
|
||
import org.bdware.analysis.taint.TaintBB;
|
||
import org.bdware.analysis.taint.TaintCFG;
|
||
import org.bdware.analysis.taint.TaintResult;
|
||
import org.bdware.doip.audit.EndpointConfig;
|
||
import org.bdware.sc.ContractResult.Status;
|
||
import org.bdware.sc.bean.*;
|
||
import org.bdware.sc.boundry.JavaScriptEntry;
|
||
import org.bdware.sc.boundry.Resources;
|
||
import org.bdware.sc.boundry.utils.RocksDBUtil;
|
||
import org.bdware.sc.boundry.utils.UtilRegistry;
|
||
import org.bdware.sc.compiler.YJSCompiler;
|
||
import org.bdware.sc.conn.ByteUtil;
|
||
import org.bdware.sc.conn.ServiceServer;
|
||
import org.bdware.sc.conn.SocketGet;
|
||
import org.bdware.sc.engine.DesktopEngine;
|
||
import org.bdware.sc.engine.JSONTool;
|
||
import org.bdware.sc.engine.hook.*;
|
||
import org.bdware.sc.handler.ContractHandler;
|
||
import org.bdware.sc.handler.DOOPRequestHandler;
|
||
import org.bdware.sc.index.TimeSerialIndex;
|
||
import org.bdware.sc.node.*;
|
||
import org.bdware.sc.server.DoipClusterServer;
|
||
import org.bdware.sc.trace.ProgramPointCounter;
|
||
import org.bdware.sc.util.FileUtil;
|
||
import org.bdware.sc.util.HashUtil;
|
||
import org.bdware.sc.util.JsonUtil;
|
||
import org.objectweb.asm.ClassReader;
|
||
import org.objectweb.asm.tree.ClassNode;
|
||
import org.objectweb.asm.tree.MethodNode;
|
||
|
||
import javax.script.ScriptContext;
|
||
import javax.script.ScriptEngine;
|
||
import javax.script.ScriptException;
|
||
import java.io.*;
|
||
import java.lang.reflect.Method;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.text.SimpleDateFormat;
|
||
import java.util.*;
|
||
import java.util.zip.ZipFile;
|
||
|
||
public class ContractProcess {
|
||
private static final byte[] ZIP_HEADER_1 = new byte[]{80, 75, 3, 4};
|
||
private static final byte[] ZIP_HEADER_2 = new byte[]{80, 75, 5, 6};
|
||
private static final org.apache.logging.log4j.Logger LOGGER =
|
||
org.apache.logging.log4j.LogManager.getLogger(ContractProcess.class);
|
||
public static ContractProcess instance;
|
||
|
||
public final String cmi;
|
||
public final ContractHandler handler;
|
||
private final Set<String> cachedRequests = new HashSet<>();
|
||
public ServiceServer server;
|
||
public DesktopEngine engine;
|
||
String dbPath;
|
||
String dir;
|
||
Contract contract;
|
||
ProjectConfig projectConfig;
|
||
ContractNode cn;
|
||
DumpTask dt;
|
||
Map<String, String> isOpen = new HashMap<>();
|
||
long gasLimit = 0;
|
||
Map<String, String> logDetails = new HashMap<>();
|
||
String memorySet; // from manifest
|
||
HashMap<String, CFGraph> CFGmap = new HashMap<>();
|
||
HashMap<String, Long> ppCountMap = new HashMap<>();
|
||
List<String> function = new ArrayList<>();
|
||
private TimeSerialIndex logIndex;
|
||
private RocksDBUtil edion;
|
||
private String pid;
|
||
public DOOPRequestHandler doopRequestHandler;
|
||
|
||
public ContractProcess(int port, String cmi) {
|
||
handler = new ContractHandler(this);
|
||
this.server = new ServiceServer(handler, port);
|
||
this.cmi = cmi;
|
||
}
|
||
|
||
public static void main(String[] args) {
|
||
int port = 1616;
|
||
String cmi = "";
|
||
InputStream pidInput = System.in;
|
||
for (String arg : args) {
|
||
if (arg.startsWith("-port")) {
|
||
String portStr = arg.substring(6);
|
||
if (portStr.replaceAll("\\d+", "").isEmpty()) {
|
||
port = Integer.parseInt(portStr);
|
||
}
|
||
} else if (arg.startsWith("-cmi")) {
|
||
cmi = arg.substring(5);
|
||
} else if (arg.startsWith("-debug")) {
|
||
LOGGER.info("log level: debug");
|
||
Configurator.setRootLevel(Level.DEBUG);
|
||
} else if (arg.startsWith("-disablePID")) {
|
||
pidInput = new ByteArrayInputStream("CP PID:-1".getBytes(StandardCharsets.UTF_8));
|
||
}
|
||
}
|
||
Scanner sc = new Scanner(pidInput);
|
||
for (String str; sc.hasNextLine(); ) {
|
||
str = sc.nextLine();
|
||
LOGGER.info("[CP From STDIN] " + str);
|
||
if (str.contains("CP PID:")) {
|
||
int pid = Integer.parseInt(str.replace("CP PID:", ""));
|
||
System.setProperty("io.netty.processId", pid + "");
|
||
LOGGER.info("[CP SET PID DONE] " + str);
|
||
break;
|
||
}
|
||
}
|
||
LOGGER.info("[Create CP]");
|
||
instance = new ContractProcess(port, cmi);
|
||
}
|
||
|
||
public static boolean isArchiveFile(File file) {
|
||
if (null == file) {
|
||
return false;
|
||
}
|
||
|
||
if (file.isDirectory()) {
|
||
return false;
|
||
}
|
||
|
||
boolean isArchive = false;
|
||
try (InputStream input = new FileInputStream(file)) {
|
||
byte[] buffer = new byte[4];
|
||
int length = input.read(buffer, 0, 4);
|
||
if (length == 4) {
|
||
isArchive =
|
||
(Arrays.equals(ZIP_HEADER_1, buffer))
|
||
|| (Arrays.equals(ZIP_HEADER_2, buffer));
|
||
}
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
return isArchive;
|
||
}
|
||
|
||
public static long toByte(String size) {
|
||
String[] unit = {"B", "KB", "MB", "GB", "TB"};
|
||
|
||
long res;
|
||
String[] a = size.split(" ");
|
||
double r = Double.parseDouble(a[0]);
|
||
|
||
if (a[1].equals(unit[1])) {
|
||
r = Math.pow(1024, 1);
|
||
} else if (a[1].equals(unit[2])) {
|
||
r = Math.pow(1024, 2);
|
||
} else if (a[1].equals(unit[3])) {
|
||
r = Math.pow(1024, 3);
|
||
} else if (a[1].equals(unit[4])) {
|
||
r = Math.pow(1024, 4);
|
||
}
|
||
|
||
res = (long) r;
|
||
return res;
|
||
}
|
||
|
||
public static String getContractDir() {
|
||
if (null != instance && null != instance.cn && null != instance.cn.getContractName()) {
|
||
return instance.cn.getContractName();
|
||
}
|
||
return "debug";
|
||
}
|
||
|
||
public String getContractName() {
|
||
return cn.getContractName();
|
||
}
|
||
|
||
public String staticVerify(Contract c) {
|
||
// ContractResult ret = new ContractResult(Status.Exception, "");
|
||
LOGGER.info("ccccc--cccc" + JsonUtil.toJson(c) + "\n" + c.getPublicKey());
|
||
ContractResult ret = new ContractResult(Status.Error, new JsonPrimitive(""));
|
||
try {
|
||
String script = c.getScriptStr();
|
||
ContractNode cn;
|
||
YJSCompiler compiler = new YJSCompiler();
|
||
if (script.startsWith("/")) {
|
||
ZipFile zf = new ZipFile(script);
|
||
ContractZipBundle czb = compiler.compile(zf);
|
||
|
||
cn = czb.mergeContractNode();
|
||
} else {
|
||
cn =
|
||
compiler.compile(
|
||
new ByteArrayInputStream(script.getBytes()), "contract_main.yjs");
|
||
}
|
||
DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf);
|
||
engine.loadContract(c, cn, ret.isInsnLimit);
|
||
Map<String, byte[]> clzs = engine.dumpClass();
|
||
Map<String, MethodNode> methods = new HashMap<>();
|
||
for (byte[] clz : clzs.values()) {
|
||
ClassNode classNode = new ClassNode();
|
||
ClassReader cr = new ClassReader(clz);
|
||
cr.accept(classNode, ClassReader.EXPAND_FRAMES);
|
||
for (MethodNode mn : classNode.methods) {
|
||
methods.put(mn.name, mn);
|
||
}
|
||
}
|
||
JsonObject result = new JsonObject();
|
||
for (FunctionNode fn : cn.getFunctions()) {
|
||
System.out.println("[ContractManager] verify:" + fn.functionName);
|
||
|
||
MethodNode mn = methods.get(fn.functionName);
|
||
if (mn != null) {
|
||
System.out.println(
|
||
"[ContractManager] getMethodNode, verify:" + fn.functionName);
|
||
TaintResult.nLocals = mn.maxLocals;
|
||
TaintResult.nStack = mn.maxStack;
|
||
TaintCFG cfg = new TaintCFG(mn);
|
||
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
|
||
try {
|
||
MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg);
|
||
analysis.analysis();
|
||
TaintBB bb = cfg.getLastBlock();
|
||
if (bb != null)
|
||
result.addProperty(fn.functionName, bb.getResultWithTaintBit());
|
||
System.out.println("[ContractManager] verifyDone:" + fn.functionName);
|
||
} catch (Exception e) {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
e.printStackTrace(new PrintStream(bo));
|
||
result.addProperty(fn.functionName, bo.toString());
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
}
|
||
ret.status = Status.Success;
|
||
ret.result = result;
|
||
} catch (Exception e) {
|
||
ret.status = Status.Exception;
|
||
JsonObject a = new JsonObject();
|
||
a.addProperty("info", e.getMessage());
|
||
ret.result = a;
|
||
e.printStackTrace();
|
||
}
|
||
return JsonUtil.toJson(ret);
|
||
}
|
||
|
||
public String getControlFlow(Contract c) {
|
||
try {
|
||
// String parameters = c.getOwner();
|
||
c.setPublicKey("temporypubkey");
|
||
long start = System.currentTimeMillis();
|
||
ContractNode cn;
|
||
DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf);
|
||
YJSCompiler compiler = new YJSCompiler();
|
||
cn = compiler.compile(new ZipFile(c.getScriptStr())).mergeContractNode();
|
||
engine.loadContract(c, cn, false);
|
||
Map<String, byte[]> clzs = engine.dumpClass();
|
||
Map<String, MethodNode> methods = new HashMap<>();
|
||
for (byte[] clz : clzs.values()) {
|
||
ClassNode classNode = new ClassNode();
|
||
ClassReader cr = new ClassReader(clz);
|
||
cr.accept(classNode, ClassReader.EXPAND_FRAMES);
|
||
for (MethodNode mn : classNode.methods) {
|
||
methods.put(mn.name, mn);
|
||
}
|
||
}
|
||
Map<String, FrontCF> result = new HashMap<>();
|
||
for (FunctionNode fn : cn.getFunctions()) {
|
||
System.out.println("[ContractManager] getCFG:" + fn.functionName);
|
||
MethodNode mn = methods.get(fn.functionName);
|
||
if (mn != null) {
|
||
/*
|
||
* CFGraph cfg = new CFGraph(mn) {
|
||
*
|
||
* @Override public BasicBlock getBasicBlock(int id) { return new
|
||
* BasicBlock(id); } }; FrontCF frontCF = new FrontCF(graph); String[]
|
||
data =
|
||
* fn.plainText().split("\n"); for (int i = 0; i <
|
||
graph.getBasicBlockSize();
|
||
* i++) { BasicBlock bb = graph.getBasicBlockAt(i); String decompiled =
|
||
""; if
|
||
* (bb.lineNum - 1 < data.length && bb.lineNum > 0) { decompiled =
|
||
* data[bb.lineNum - 1]; } frontCF.addBB(bb, decompiled); Set<BasicBlock>
|
||
suc =
|
||
* graph.getSucBlocks(bb); for (BasicBlock sucBB : suc)
|
||
frontCF.addEdge(bb,
|
||
* sucBB); }
|
||
*/
|
||
TaintResult.nLocals = mn.maxLocals;
|
||
TaintResult.nStack = mn.maxStack;
|
||
TaintCFG cfg = new TaintCFG(mn);
|
||
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
|
||
MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg);
|
||
// ByValueDependencyAnalysis
|
||
analysis.analysis();
|
||
// ControlDependencyAnalysis
|
||
Map<Integer, List<Integer>> map = MultiSourceTaintAnalysis.depAnalysis(cfg);
|
||
FrontCF frontCF = new FrontCF(cfg);
|
||
String[] data = fn.plainText().split("\n");
|
||
for (int i = 0; i < cfg.getBasicBlockSize(); i++) {
|
||
BasicBlock bb = cfg.getBasicBlockAt(i);
|
||
String decompiled = "";
|
||
if (bb.lineNum - 1 < data.length && bb.lineNum > 0) {
|
||
decompiled = data[bb.lineNum - 1];
|
||
}
|
||
List<Integer> ids = map.get(i);
|
||
frontCF.addBB(bb, decompiled, ids, cfg);
|
||
Set<BasicBlock> suc = cfg.getSucBlocks(bb);
|
||
for (BasicBlock sucBB : suc) frontCF.addEdge(bb, sucBB);
|
||
}
|
||
// get result
|
||
// TaintBB lastBlock = cfg.getLastBlock();
|
||
// if (lastBlock != null) {
|
||
// frontCF.ret = lastBlock.getResultWithTaintBit();
|
||
// // System.out.println(frontCF.ret);
|
||
// if (parameters != null && parameters != "") {
|
||
// // System.out.println(parameters);
|
||
// // frontCF.finalRet = "yes";
|
||
// Gson gson = JsonUtil;
|
||
// JsonParser jsonParser = new JsonParser();
|
||
// JsonArray jsonArray =
|
||
// jsonParser.parse(parameters).getAsJsonArray();
|
||
// List<String> listConstraint = new ArrayList<>();
|
||
// List<String> listResource = new ArrayList<>();
|
||
// for (JsonElement je : jsonArray) {
|
||
// Bean bean = gson.fromJson(je, Bean.class);
|
||
// switch (bean.name) {
|
||
// case "open":
|
||
// listConstraint.add("open");
|
||
// break;
|
||
// case "byValue":
|
||
// listConstraint.add("byValue");
|
||
// break;
|
||
// case "control":
|
||
// listConstraint.add("control");
|
||
// break;
|
||
// case "close":
|
||
// listConstraint.add("close");
|
||
// break;
|
||
// case "originalData":
|
||
// listResource.add("originalData");
|
||
// break;
|
||
// case "contractCall":
|
||
// listResource.add("contractCall");
|
||
// break;
|
||
// }
|
||
// }
|
||
//// String dep =
|
||
// frontCF.blocks.get(frontCF.blocks.size() - 1).blockDep;
|
||
//// if ((listConstraint.contains("open")
|
||
//// ||
|
||
// listConstraint.contains("close"))
|
||
//// && (frontCF.ret != null || dep != null))
|
||
//// frontCF.finalRet = "不通过";
|
||
//// else frontCF.finalRet = "通过";
|
||
// }
|
||
// }
|
||
result.put(fn.functionName, frontCF);
|
||
}
|
||
}
|
||
System.out.println("Test:" + JsonUtil.toJson(result));
|
||
long end = System.currentTimeMillis();
|
||
System.out.println(end - start);
|
||
return JsonUtil.toJson(result);
|
||
} catch (Exception e) {
|
||
// TODO Auto-generated catch block
|
||
e.printStackTrace();
|
||
}
|
||
return "{\"status\":\"failed\"}";
|
||
}
|
||
|
||
// 启动时写入数据库
|
||
private void logCode() {
|
||
Map<String, byte[]> clzs = engine.dumpClass(); // 合约字节码
|
||
// 将clzs中byte[]进行分Base64编码
|
||
|
||
Map<String, String> clzs2 = new HashMap<>();
|
||
for (String k : clzs.keySet()) {
|
||
String v = ByteUtil.encodeBASE64(clzs.get(k));
|
||
clzs2.put(k, v);
|
||
}
|
||
String code = JsonUtil.toJson(clzs2);
|
||
Map<String, String> map1 = new HashMap<>();
|
||
map1.put("contract-bytecode", code); // 合约字节码
|
||
map1.put("contractID", contract.getID());
|
||
map1.put("contractType", contract.getType().name());
|
||
// String str = ContractManager.dbPath + ";" + contractName + ";startContract" +
|
||
// ";" + map1;
|
||
map1.put("operation", "startContract");
|
||
map1.put("timestamp", System.currentTimeMillis() + "");
|
||
writeContractDB(map1);
|
||
}
|
||
|
||
// TODO
|
||
public String setDesktopPermission(String isChanged) {
|
||
try {
|
||
System.out.println("permission" + isChanged);
|
||
String[] pmList = isChanged.split(",");
|
||
String yancloud_desktop = "";
|
||
isOpen.put(pmList[0], pmList[1]);
|
||
yancloud_desktop += UtilRegistry.getInitStr(pmList[0], pmList[1].equals("open"));
|
||
engine.getNashornEngine()
|
||
.getContext()
|
||
.setAttribute(
|
||
ScriptEngine.FILENAME, yancloud_desktop, ScriptContext.ENGINE_SCOPE);
|
||
engine.getNashornEngine().eval(yancloud_desktop);
|
||
} catch (ScriptException e) {
|
||
e.printStackTrace();
|
||
}
|
||
return "success";
|
||
}
|
||
|
||
public String getMemorySet() {
|
||
if (null == memorySet) {
|
||
return "";
|
||
}
|
||
return this.memorySet;
|
||
}
|
||
|
||
public String getLogType(String funName) {
|
||
return logDetails.get(funName);
|
||
}
|
||
|
||
// 判断是否满足Oracle和Contact的执行要求
|
||
public String verifyOracleAndContractPermission(Contract contract) {
|
||
// 权限校验 如果是Oracle 启动方式只能是Sole 否则报错
|
||
if (cn.getYjsType() == YjsType.Oracle && contract.getType() != ContractExecType.Sole && contract.getType() != ContractExecType.Sharding) {
|
||
LOGGER.info("Oracle only support Sole ContractType!");
|
||
return JsonUtil.toJson(
|
||
new ContractResult(
|
||
Status.Error,
|
||
new JsonPrimitive("Oracle only support Sole ContractType!")));
|
||
}
|
||
// 权限校验 如果是contract 申请了MySQL等权限 报错
|
||
if (cn.getYjsType() == YjsType.Contract) {
|
||
for (Permission per : cn.getPermission()) {
|
||
if (per == Permission.SQL
|
||
|| per == Permission.Http
|
||
|| per == Permission.RocksDB
|
||
|| per == Permission.MongoDB) {
|
||
LOGGER.debug("Contract can not have permissions of IO!");
|
||
return JsonUtil.toJson(
|
||
new ContractResult(
|
||
Status.Error,
|
||
new JsonPrimitive("Contract can not have permissions of IO|")));
|
||
}
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
|
||
public String setMembers(List<String> members) {
|
||
JavaScriptEntry.members = members;
|
||
if (members != null)
|
||
return members.size() + "";
|
||
else return "0";
|
||
}
|
||
|
||
public String setContractBundle(Contract contract) {
|
||
try {
|
||
// long start = System.currentTimeMillis();
|
||
// long start0 = start;
|
||
this.contract = contract;
|
||
JavaScriptEntry.random = new Random();
|
||
JavaScriptEntry.invokeID = 0L;
|
||
JavaScriptEntry.random.setSeed(Integer.parseInt(contract.getID()));
|
||
JavaScriptEntry.numOfCopies = this.contract.getNumOfCopies();
|
||
JavaScriptEntry.shardingID =
|
||
this.contract.getShardingId(); // 设置javaScriptEntry中的shardingID
|
||
// JavaScriptEntry
|
||
String zipPath = contract.getScriptStr();
|
||
if (isArchiveFile(new File(zipPath))) {
|
||
ZipFile zf = new ZipFile(zipPath);
|
||
ContractZipBundle zipBundle = new YJSCompiler().compile(zf);
|
||
cn = zipBundle.mergeContractNode();
|
||
// check functionNodes
|
||
List<FunctionNode> functionNodes = cn.getFunctions();
|
||
injectHandlers();
|
||
|
||
this.contract.setYjsType(cn.getYjsType());
|
||
memorySet = cn.memorySet;
|
||
this.contract.sourcePath = zipBundle.getManifest().sourcePath;
|
||
|
||
LOGGER.debug(
|
||
"check sourcePath\n\tin-contract="
|
||
+ this.contract.sourcePath
|
||
+ "\n\tin-manifest="
|
||
+ zipBundle.getManifest().sourcePath);
|
||
// zhanghongwei
|
||
|
||
/* if (ret.getManifest().getInsnLimit() != 0) {
|
||
gasLimit=ret.getManifest().getInsnLimit();
|
||
isInsnLimit = true;
|
||
}*/
|
||
String ver = verifyOracleAndContractPermission(contract);
|
||
if (!ver.isEmpty()) {
|
||
return ver;
|
||
}
|
||
|
||
for (Permission per : cn.getPermission()) {
|
||
isOpen.put(per.name(), "open");
|
||
}
|
||
|
||
handleLog();
|
||
// System.out.println("[ret.getManifest().getInsnLimit()]" +
|
||
// ret.getManifest().getInsnLimit());
|
||
engine = new DesktopEngine(zipBundle.getManifest(), zipPath, contract);
|
||
engine.loadJar(zf);
|
||
engine.registerResource(new Resources(zf, engine.getClassLoad()));
|
||
ContractResult result = engine.loadContract(contract, cn, cn.getInstrumentBranch());
|
||
JsonObject jo = new JsonObject();
|
||
ContractResult onCreate = invokeOnCreate(contract.getCreateParam());
|
||
jo.add("onCreate", JsonUtil.parseObject(onCreate));
|
||
jo.add("loadContract", JsonUtil.parseObject(result));
|
||
jo.addProperty("status", result.status.merge(onCreate.status).toString());
|
||
LOGGER.debug("result: " + jo.toString());
|
||
// doipModule的话,拉起DoipServer服务端口
|
||
if (cn.hasDoipModule()) {
|
||
// 只有一台机器去更新Router中的repoInfo就可以了
|
||
updateRepoInfo(contract.getCreateParam());
|
||
invokeOnStartingDoipServer(cn, contract.getCreateParam(), jo);
|
||
}
|
||
return jo.toString();
|
||
} else {
|
||
contract.setScript(FileUtil.getFileContent(zipPath));
|
||
return setContract(contract);
|
||
}
|
||
|
||
} catch (MalformedJsonException | JsonSyntaxException e) {
|
||
return JsonUtil.toJson(
|
||
new ContractResult(
|
||
Status.Error,
|
||
new JsonPrimitive("parse manifest.json error, not json format!")));
|
||
} catch (Exception e) {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
e.printStackTrace(new PrintStream(bo));
|
||
return JsonUtil.toJson(
|
||
new ContractResult(Status.Error, new JsonPrimitive(bo.toString())));
|
||
}
|
||
}
|
||
|
||
private void injectHandlers() throws Exception {
|
||
// 正式启动
|
||
if (!this.contract.isDebug()) {
|
||
// this.engine.getResources().loadAsString("/maskConfig.json");
|
||
for (FunctionNode fun : cn.getFunctions()) {
|
||
|
||
if (fun.isExport()) {
|
||
// System.out.println("isExport");
|
||
fun.appendBeforeInvokeHandler(new MockTemplateHandler());
|
||
|
||
}
|
||
}
|
||
}
|
||
DOOPBeforeExecHandler doopBeforeExecHandler = null;
|
||
DOOPAfterExecHandler doopAfterExecHandler = null;
|
||
doopRequestHandler = null;
|
||
for (FunctionNode fun : cn.getFunctions()) {
|
||
if (fun.isConfidential()) {
|
||
fun.appendBeforeInvokeHandler(new ConfidentialHandler(fun));
|
||
}
|
||
ArgSchemaHandler argSchemaHandler = createHandlerIfExist(fun, ArgSchemaHandler.class);
|
||
if (argSchemaHandler != null) {
|
||
fun.appendBeforeInvokeHandler(argSchemaHandler);
|
||
}
|
||
|
||
if (fun.isExport()) {
|
||
//if(fun.annotations...)
|
||
AccessHandler accessHandler = createHandlerIfExist(fun, AccessHandler.class);
|
||
if (accessHandler != null) {
|
||
fun.appendBeforeInvokeHandler(accessHandler);
|
||
}
|
||
fun.appendAfterInvokeHandler(new ObjToJsonHandler());
|
||
// fun.appendBeforeInvokeHandler(new ReadMeHandler());
|
||
// Mask是用于返回真正结果之后,做一些偏移,以保护数据隐私。
|
||
// if (fun.isMask()) {
|
||
|
||
// String maskConfig =
|
||
// engine.getResources().loadAsString("/maskConfig.json");
|
||
// System.out.println("injectMask"+maskConfig);
|
||
// System.out.println("injectMask"+this.contract.Mask);
|
||
fun.appendAfterInvokeHandler(new MaskHandler());
|
||
// }
|
||
}
|
||
if (fun.isHomomorphicEncrypt()) {
|
||
LOGGER.info("injectHandlers--------------------------------1");
|
||
fun.appendAfterInvokeHandler(new HomomorphicEncryptHandler(fun));
|
||
}
|
||
if (fun.isHomomorphicDecrypt()) {
|
||
fun.appendAfterInvokeHandler(new HomomorphicDecryptHandler(fun));
|
||
}
|
||
|
||
if (fun.isDoipOperation()) {
|
||
if (doopRequestHandler == null) {
|
||
doopRequestHandler = new DOOPRequestHandler();
|
||
}
|
||
fun.appendBeforeInvokeHandler(new DOOPBeforeExecHandler(fun.getDoipOperationInfo().operation));
|
||
fun.appendAfterInvokeHandler(new DOOPAfterExecHandler(fun.getDoipOperationInfo().operation));
|
||
doopRequestHandler.addDoipOperation(fun);
|
||
}
|
||
}
|
||
}
|
||
|
||
<T extends AnnotationHook> T createHandlerIfExist(FunctionNode function, Class<T> clz) {
|
||
YJSAnnotation annotation = clz.getAnnotation(YJSAnnotation.class);
|
||
if (annotation == null) return null;
|
||
try {
|
||
AnnotationNode node = function.getAnnotation(annotation.name());
|
||
if (node == null) return null;
|
||
Method m = clz.getDeclaredMethod("fromAnnotationNode", FunctionNode.class, AnnotationNode.class);
|
||
T result = (T) m.invoke(null, function, node);
|
||
return result;
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public String changeDumpPeriod(String period) {
|
||
System.out.println("[ContractProcess] period" + period);
|
||
|
||
startAutoDump();
|
||
return "success";
|
||
}
|
||
|
||
public String getDumpPeriod() {
|
||
return projectConfig.getDumpPeriod();
|
||
}
|
||
|
||
public String setContract(Contract contract) {
|
||
try {
|
||
JavaScriptEntry.random = new Random();
|
||
JavaScriptEntry.invokeID = 0L;
|
||
JavaScriptEntry.random.setSeed(Integer.parseInt(contract.getID()));
|
||
JavaScriptEntry.numOfCopies = contract.getNumOfCopies();
|
||
// TODO Optimize, 4 seconds takes to create an Engine.
|
||
engine = new DesktopEngine();
|
||
this.contract = contract;
|
||
this.contract.sourcePath = "script_" + System.currentTimeMillis();
|
||
YJSCompiler compiler = new YJSCompiler();
|
||
cn = compiler.compile(contract.getScript(), null); // 这一步初始化ContractNode
|
||
contract.setYjsType(cn.getYjsType());
|
||
|
||
injectHandlers();
|
||
String ver = verifyOracleAndContractPermission(contract);
|
||
if (!ver.equals("")) {
|
||
return ver;
|
||
}
|
||
handleLog();
|
||
LOGGER.info("load script, contract:" + JsonUtil.toJson(contract.getScriptStr()));
|
||
LOGGER.info("load cn:" + JsonUtil.toJson(cn));
|
||
ContractResult ret =
|
||
engine.loadContract(contract, cn, cn.getInstrumentBranch());
|
||
ContractResult onCreate = invokeOnCreate(contract.getCreateParam());
|
||
JsonObject jo = new JsonObject();
|
||
jo.add("onCreate", JsonUtil.parseObject(onCreate));
|
||
jo.add("loadContract", JsonUtil.parseObject(ret));
|
||
jo.addProperty("status", ret.status.merge(onCreate.status).toString());
|
||
LOGGER.debug("result: " + jo.toString());
|
||
|
||
// doipModule的话,拉起DoipServer服务端口
|
||
if (cn.getYjsType() == YjsType.DoipModule) {
|
||
updateRepoInfo(contract.getCreateParam());
|
||
invokeOnStartingDoipServer(cn, contract.getCreateParam(), jo);
|
||
}
|
||
|
||
return jo.toString();
|
||
} catch (Exception e) {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
e.printStackTrace(new PrintStream(bo));
|
||
return JsonUtil.toJson(
|
||
new ContractResult(Status.Error, new JsonPrimitive(bo.toString())));
|
||
}
|
||
}
|
||
|
||
public void updateRepoInfo(JsonElement arg) throws Exception {
|
||
// 只有0号节点需要初始化IRP连接去updateRepoInfo
|
||
if (JavaScriptEntry.shardingID == 0) {
|
||
// DOOP relevant logic
|
||
DoipClusterServer server = DoipClusterServer.getDOOPServerInstance();
|
||
if (server == null) {
|
||
JsonObject createParams = arg.getAsJsonObject();
|
||
if (createParams.has("router")) {
|
||
JsonElement routerInfo = createParams.get("router");
|
||
if (!routerInfo.isJsonObject())
|
||
throw new Exception("Provide wrong router info in create params to DoipModule");
|
||
else {
|
||
EndpointConfig endpointConfig = JsonUtil.GSON.fromJson(routerInfo.getAsJsonObject(), EndpointConfig.class);
|
||
DoipClusterServer.createDOOPServerInstance(endpointConfig);
|
||
}
|
||
} else {
|
||
throw new Exception("DoipModule should provide router info in create params");
|
||
}
|
||
|
||
server = DoipClusterServer.getDOOPServerInstance();
|
||
}
|
||
// 只有一台机器去更新Router中的repoInfo就可以了
|
||
|
||
server.updateRepoInfo(contract, cn);
|
||
}
|
||
}
|
||
|
||
public void invokeOnStartingDoipServer(ContractNode cn, JsonElement arg, JsonObject returnValue) {
|
||
ContractRequest onStartingDoipServer = new ContractRequest();
|
||
onStartingDoipServer.setAction("onServerStart");
|
||
if (arg == null) {
|
||
if (engine != null && engine.getManifest() != null && engine.getManifest().createParam != null)
|
||
arg = engine.getManifest().createParam;
|
||
else
|
||
arg = new JsonPrimitive("");
|
||
}
|
||
onStartingDoipServer.setArg(arg);
|
||
LOGGER.debug("invoke onStartingDoipServer, param:" + onStartingDoipServer.getArg().toString());
|
||
onStartingDoipServer.setRequester(contract.getOwner());
|
||
if (contract.getDoipFlag() && null != contract.getDOI() && !contract.getDOI().isEmpty()) {
|
||
onStartingDoipServer.setRequesterDOI(contract.getDOI());
|
||
} else {
|
||
onStartingDoipServer.setRequesterDOI("empty");
|
||
}
|
||
FunctionNode funNode = cn.getFunction("onServerStart");
|
||
|
||
try {
|
||
JsonElement onStartingDoipServerRes = invoke(onStartingDoipServer, funNode).result;
|
||
returnValue.add("doipModuleStartResult", onStartingDoipServerRes);
|
||
int startPort = ContractProcess.instance.server.getPort() + 1;
|
||
if (arg.isJsonObject() && arg.getAsJsonObject().has("doipStartPort")) {
|
||
startPort = arg.getAsJsonObject().get("doipStartPort").getAsInt();
|
||
}
|
||
LOGGER.info("Fetch the onStartingDoipServerRes from router successfully, the result is " + onStartingDoipServerRes);
|
||
int doipListenPort = DoipClusterServer.startDoipServer(startPort);
|
||
returnValue.addProperty("doipListenPort", doipListenPort);
|
||
returnValue.addProperty("doipStartPort", startPort);
|
||
} catch (Exception e) {
|
||
LOGGER.error("DoipLocalSingleton cannot starts properly, plz check the onServerStart function");
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
private void handleLog() {
|
||
for (FunctionNode fun : cn.getFunctions()) {
|
||
StringBuilder detail = new StringBuilder();
|
||
|
||
for (LogType type : fun.getLogTypes()) {
|
||
switch (type) {
|
||
case Arg:
|
||
detail.append("Arg;");
|
||
break;
|
||
case Branch:
|
||
detail.append("Branch;");
|
||
break;
|
||
case Result:
|
||
detail.append("Result;");
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (fun.getLogToBDContract()) detail.append("bdcontract;");
|
||
if (fun.getLogToNamedLedger()) {
|
||
for (String str : fun.getLedgerNames()) {
|
||
detail.append("bdledger:").append(str).append(";");
|
||
}
|
||
}
|
||
logDetails.put(fun.functionName, detail.toString());
|
||
}
|
||
}
|
||
|
||
public String setDBInfo(String path) {
|
||
dbPath = path;
|
||
/*
|
||
* File confDB = new File(path); if (!confDB.exists()) confDB.mkdirs();
|
||
*/
|
||
return "success";
|
||
}
|
||
|
||
public long getUsedMemory(String arg) {
|
||
Runtime r = Runtime.getRuntime();
|
||
return r.totalMemory() - r.freeMemory();
|
||
}
|
||
|
||
private ContractResult invokeOnCreate(JsonElement arg) {
|
||
long start = System.currentTimeMillis();
|
||
logIndex = new TimeSerialIndex("./ContractDB/" + cn.getContractName() + ".index");
|
||
LOGGER.debug("timeSerialIndex: " + (System.currentTimeMillis() - start));
|
||
start = System.currentTimeMillis();
|
||
edion = RocksDBUtil.loadDB("defaultLog", false);
|
||
LOGGER.debug("create RocksDB: " + (System.currentTimeMillis() - start));
|
||
start = System.currentTimeMillis();
|
||
engine.redirectTracePS(new Logger(new ByteArrayOutputStream(), this));
|
||
// startContract时写入数据库
|
||
if (null != cn.getLogTypes() && cn.getLogTypes().contains(LogType.Code)) {
|
||
logCode();
|
||
}
|
||
|
||
JavaScriptEntry.setSM2KeyPair(contract.getPublicKey(), contract.getKey());
|
||
if (null != contract.getDOI() && !contract.getDOI().isEmpty()) {
|
||
JavaScriptEntry.doi = contract.getDOI();
|
||
}
|
||
if (null != contract.getAuthInfoPersistDOI()
|
||
&& !contract.getAuthInfoPersistDOI().isEmpty()) {
|
||
JavaScriptEntry.authInfoPersistDOI = contract.getAuthInfoPersistDOI();
|
||
}
|
||
JavaScriptEntry.isDebug = contract.isDebug();
|
||
ContractRequest onCreate = new ContractRequest();
|
||
onCreate.setAction("onCreate");
|
||
if (arg == null) {
|
||
if (engine != null && engine.getManifest() != null && engine.getManifest().createParam != null)
|
||
arg = engine.getManifest().createParam;
|
||
else
|
||
arg = new JsonPrimitive("");
|
||
}
|
||
onCreate.setArg(arg);
|
||
LOGGER.debug("invoke onCreate, param:" + onCreate.getArg().toString());
|
||
onCreate.setRequester(contract.getOwner());
|
||
if (contract.getDoipFlag() && null != contract.getDOI() && !contract.getDOI().isEmpty()) {
|
||
onCreate.setRequesterDOI(contract.getDOI());
|
||
} else {
|
||
onCreate.setRequesterDOI("empty");
|
||
}
|
||
FunctionNode funNode = cn.getFunction("onCreate");
|
||
return invoke(onCreate, funNode);
|
||
}
|
||
|
||
public void resetContractName(String name) {
|
||
if (name != null)
|
||
cn.resetContractName(name);
|
||
}
|
||
|
||
private ContractResult invokeOnRecover(JsonElement arg) {
|
||
ContractRequest onRecover = new ContractRequest();
|
||
onRecover.setAction("onRecover");
|
||
if (arg == null)
|
||
onRecover.setArg("null");
|
||
else
|
||
onRecover.setArg(arg);
|
||
onRecover.setRequester(contract.getOwner());
|
||
if (contract.getDoipFlag()
|
||
&& (contract.getDOI() != null)
|
||
&& (contract.getDOI().length() > 0)) {
|
||
onRecover.setRequesterDOI(contract.getDOI());
|
||
} else {
|
||
onRecover.setRequesterDOI("empty");
|
||
}
|
||
FunctionNode funNode = cn.getFunction("onRecover");
|
||
return invoke(onRecover, funNode);
|
||
}
|
||
|
||
private ContractResult invoke(ContractRequest onRecover, FunctionNode funNode) {
|
||
if (funNode != null) {
|
||
funNode.setIsExport(true);
|
||
ContractResult result = engine.executeContract(onRecover);
|
||
funNode.setIsExport(false);
|
||
engine.getTracePS().clean();
|
||
return result;
|
||
}
|
||
return new ContractResult(Status.Success, new JsonPrimitive("no funNode found"));
|
||
}
|
||
|
||
// public String executeBundle(ContractZipBundle czb, String arg) {
|
||
// ContractRequest ac = null;
|
||
// ContractResult result = null;
|
||
// try {
|
||
// ac = JsonUtil.fromJson(arg, ContractRequest.class);
|
||
// } catch (Exception e) {
|
||
// }
|
||
// if (ac == null) {
|
||
// result = new ContractResult(ContractResult.Status.Error, "Illegal
|
||
// Arguments!");
|
||
// return JsonUtil.toJson(result);
|
||
// }
|
||
//
|
||
// ContractManifest cm = czb.getManifest();
|
||
// switch (cm.getType()) {
|
||
// case Data:
|
||
// case Algorithm:
|
||
// result = engine.executeContract(ac);
|
||
// return JsonUtil.toJson(result);
|
||
// case Application:
|
||
// default:
|
||
// return "todo";
|
||
// }
|
||
// }
|
||
|
||
public boolean isSigRequired() {
|
||
return cn.sigRequired;
|
||
}
|
||
|
||
public String requestLog(long offset, int size) {
|
||
List<Long> hashes = logIndex.request(offset, size);
|
||
List<Map<String, String>> jo = new ArrayList<>();
|
||
|
||
TypeToken<Map<String, String>> token = new TypeToken<Map<String, String>>() {
|
||
};
|
||
for (Long hash : hashes)
|
||
try {
|
||
Map<String, String> obj =
|
||
JsonUtil.fromJson(edion.get(hash.toString()), token.getType());
|
||
jo.add(obj);
|
||
} catch (JsonSyntaxException e) {
|
||
e.printStackTrace();
|
||
}
|
||
return JsonUtil.toJson(jo);
|
||
}
|
||
|
||
public String requestLast(int count) {
|
||
List<Long> hashes = logIndex.requestLast(count);
|
||
List<Map<String, String>> jo = new ArrayList<>();
|
||
TypeToken<Map<String, String>> token = new TypeToken<Map<String, String>>() {
|
||
};
|
||
String log;
|
||
for (Long hash : hashes)
|
||
try {
|
||
log = edion.get(hash.toString());
|
||
if (null == log || 0 == log.length()) {
|
||
continue;
|
||
}
|
||
Map<String, String> obj = JsonUtil.fromJson(log, token.getType());
|
||
if (obj == null) {
|
||
System.out.println(
|
||
"[ContractProcess] requestLast, parseJsonError:" + log + "==");
|
||
continue;
|
||
}
|
||
obj.put("hash", hash + "");
|
||
jo.add(obj);
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
return JsonUtil.toJson(jo);
|
||
}
|
||
|
||
public long logSize() {
|
||
return logIndex.size();
|
||
}
|
||
|
||
public String executeFunctionWithoutLimit(String arg) {
|
||
try {
|
||
JsonObject body = JsonUtil.parseString(arg).getAsJsonObject();
|
||
String funcName = body.get("funcName").getAsString();
|
||
JsonArray arr = body.getAsJsonArray("funcArgs");
|
||
Object[] funcArgs = new Object[arr.size()];
|
||
for (int i = 0; i < arr.size(); i++) {
|
||
funcArgs[i] = JSONTool.convertJsonElementToMirror(arr.get(i));
|
||
}
|
||
Object result = engine.invokeFunction(funcName, funcArgs);
|
||
result = JSONTool.convertMirrorToJson(result);
|
||
return JsonUtil.toJson(result);
|
||
} catch (Exception e) {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
e.printStackTrace(new PrintStream(bo));
|
||
return bo.toString();
|
||
}
|
||
}
|
||
|
||
public String executeContract(String arg) {
|
||
// TODO
|
||
// eventCenter.pub(new EventMsg("executeContract", arg));
|
||
ContractRequest request;
|
||
ContractResult result;
|
||
|
||
try {
|
||
request = JsonUtil.fromJson(arg, ContractRequest.class);
|
||
} catch (Exception ignored) {
|
||
result =
|
||
new ContractResult(
|
||
ContractResult.Status.Error, new JsonPrimitive("Illegal Arguments!"));
|
||
return JsonUtil.toJson(result);
|
||
}
|
||
String reqID = request.getRequestID();
|
||
if (cachedRequests.contains(reqID)) {
|
||
LOGGER.info("[Hit Cache]:" + reqID);
|
||
try {
|
||
String cachedResult = edion.get(reqID);
|
||
if (cachedResult != null && !cachedResult.isEmpty()) {
|
||
return cachedResult;
|
||
}
|
||
} catch (Exception ignored) {
|
||
}
|
||
}
|
||
try {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
if (request.withDynamicAnalysis) {
|
||
ContractProcess.Logger previous = engine.getTracePS();
|
||
engine.redirectTracePS(new Logger(bo, this));
|
||
result = engine.executeContract(request);
|
||
result.analysis = bo.toString();
|
||
System.out.println(
|
||
"[ContractProcess] result.analysis = "
|
||
+ result.analysis); // 动态分析bug null pointer
|
||
// branchResult = JsonUtil.toJson(result);
|
||
// branchTrace = result.analysis;
|
||
engine.redirectTracePS(previous);
|
||
dynamicAnalysis(request, result);
|
||
} else if (request.withEvaluatesAnalysis) {
|
||
ContractProcess.Logger previous = engine.getTracePS();
|
||
|
||
System.out.println("[size:]" + function.size());
|
||
System.out.println("[action index]:" + function.indexOf(request.getAction()));
|
||
|
||
System.out.println("[InsnFeeValue]" + request.getValue());
|
||
System.out.println("[InsnFeeLimit]" + gasLimit);
|
||
int functionIndex = function.indexOf(request.getAction());
|
||
if (ppCountMap == null || ppCountMap.isEmpty()) {
|
||
System.out.println("没有提前进行预估");
|
||
evaluatesAnalysis(request.getAction());
|
||
}
|
||
|
||
engine.redirectTracePS(
|
||
new ProgramPointCounter(
|
||
bo,
|
||
this,
|
||
gasLimit,
|
||
functionIndex,
|
||
request.getValue(),
|
||
0L,
|
||
request.getAction(),
|
||
ppCountMap));
|
||
result = engine.executeContract(request);
|
||
|
||
result.analysis = bo.toString();
|
||
engine.redirectTracePS(previous);
|
||
|
||
} else {
|
||
ContractProcess.Logger previous = engine.getTracePS();
|
||
engine.redirectTracePS(new Logger(bo, this));
|
||
result = engine.executeContract(request);
|
||
engine.redirectTracePS(previous);
|
||
}
|
||
|
||
String ret = JsonUtil.toJson(result);
|
||
if (reqID != null && reqID.endsWith("_mul")) {
|
||
cachedRequests.add(reqID);
|
||
edion.put(reqID, ret);
|
||
}
|
||
return ret;
|
||
} catch (Exception e) {
|
||
ByteArrayOutputStream bo = new ByteArrayOutputStream();
|
||
e.printStackTrace(new PrintStream(bo));
|
||
return bo.toString();
|
||
}
|
||
}
|
||
|
||
public String evaluatesAnalysis(String getFunction) {
|
||
Map<String, byte[]> clzs = engine.dumpClass();
|
||
Map<String, MethodNode> methods = new HashMap<>();
|
||
for (byte[] clz : clzs.values()) {
|
||
ClassNode classNode = new ClassNode();
|
||
ClassReader cr = new ClassReader(clz);
|
||
cr.accept(classNode, ClassReader.EXPAND_FRAMES);
|
||
for (MethodNode mn : classNode.methods) {
|
||
methods.put(mn.name, mn);
|
||
}
|
||
}
|
||
int flag = 0;
|
||
for (String s : function) {
|
||
MethodNode mn = methods.get(s);
|
||
if (mn != null) {
|
||
CFGraph cfg =
|
||
new CFGraph(mn) {
|
||
@Override
|
||
public BasicBlock getBasicBlock(int id) {
|
||
return new BasicBlock(id);
|
||
}
|
||
};
|
||
// cfg.printSelf();
|
||
CFGmap.put(s, cfg);
|
||
PPCount countFee = new PPCount(cfg, flag);
|
||
|
||
BasicBlock bb = cfg.getBasicBlockAt(0);
|
||
countFee.dfs(cfg, bb);
|
||
// System.out.println("[ppmap]:" + PPCount.ppMap);
|
||
// System.out.println("[PPCount.branchCount]"+PPCount.branchCount);
|
||
Evaluates feEvaluates = new Evaluates();
|
||
feEvaluates.getGas(PPCount.branchCount);
|
||
feEvaluates.getInsnGas(PPCount.ppMap);
|
||
|
||
PPCount.countFunction(s, Evaluates.map);
|
||
ppCountMap = Evaluates.map;
|
||
System.out.println("+++++++" + PPCount.ppMap);
|
||
flag++;
|
||
}
|
||
}
|
||
for (Map.Entry<String, Long> map : PPCount.functionSumGas.entrySet()) {
|
||
if (map.getKey().contains(getFunction) && map.getKey().contains("true")) {
|
||
System.out.println("[合约方法pub中条件循环为true时:]" + map.getValue());
|
||
} else if (map.getKey().contains(getFunction) && map.getKey().contains("false")) {
|
||
System.out.println("[合约方法pub中条件循环为false时:]" + map.getValue());
|
||
} else if (map.getKey().contains(getFunction)) {
|
||
System.out.println("[合约方法pub中其他语句消耗:]" + map.getValue());
|
||
}
|
||
}
|
||
return PPCount.functionSumGas.toString();
|
||
}
|
||
|
||
public void dynamicAnalysis(ContractRequest ac, ContractResult result) {
|
||
Map<String, byte[]> classes = engine.dumpClass();
|
||
Map<String, MethodNode> methods = new HashMap<>();
|
||
for (byte[] clz : classes.values()) {
|
||
ClassNode classNode = new ClassNode();
|
||
ClassReader cr = new ClassReader(clz);
|
||
System.out.print("[cr:]" + cr);
|
||
cr.accept(classNode, ClassReader.EXPAND_FRAMES);
|
||
for (MethodNode mn : classNode.methods) {
|
||
methods.put(mn.name, mn);
|
||
}
|
||
}
|
||
|
||
MethodNode mn = methods.get(ac.getAction());
|
||
if (mn != null) {
|
||
TaintResult.nLocals = mn.maxLocals;
|
||
TaintResult.nStack = mn.maxStack;
|
||
TaintCFG cfg = new TaintCFG(mn);
|
||
String trace = result.analysis;
|
||
System.out.println("TraceFile:\n" + trace);
|
||
System.out.println("TraceFile结束=====================================");
|
||
System.out.println("打印cfg图=====================================");
|
||
cfg.printSelf();
|
||
System.out.println("打印cfg图=====================================");
|
||
TracedFile tf = new TracedFile(new ByteArrayInputStream(trace.getBytes()));
|
||
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
|
||
NaiveDynamicTaintAnalysis analysis = new NaiveDynamicTaintAnalysis(cfg, tf);
|
||
analysis.analysis();
|
||
|
||
TaintBB bb = cfg.getLastBlock();
|
||
result.analysis = bb.getResultWithTaintBit();
|
||
System.out.println(
|
||
"[ContractProcess] dynamically verify: "
|
||
+ ac.getAction()
|
||
+ "-->"
|
||
+ result.analysis);
|
||
}
|
||
}
|
||
|
||
public String registerMangerPort(String arg) {
|
||
JavaScriptEntry.get = new SocketGet("127.0.0.1", Integer.parseInt(arg));
|
||
return "success";
|
||
}
|
||
|
||
public void subscribe(String functionName) {
|
||
cn.getFunction(functionName).setHandler(true);
|
||
cn.getFunction("_preSub").setHandler(true);
|
||
}
|
||
|
||
public void unSubscribe(String functionName) {
|
||
cn.getFunction(functionName).setHandler(false);
|
||
}
|
||
|
||
public boolean checkSub() {
|
||
return !JavaScriptEntry.topic_handlers.isEmpty();
|
||
}
|
||
|
||
public void beforeSuicide() {
|
||
}
|
||
|
||
public String redo(String path) {
|
||
return engine.syncUtil.redo(path);
|
||
}
|
||
|
||
public String getMemoryDump(String path) {
|
||
return engine.syncUtil.dumpMemory(path, contract.getStateful());
|
||
}
|
||
|
||
public String getJSERandomCur() {
|
||
return JavaScriptEntry.random.toString();
|
||
}
|
||
|
||
public String loadMemoryDump(String path) {
|
||
String str = engine.syncUtil.loadMemoryDump(path, contract.getStateful());
|
||
invokeOnRecover(contract.getCreateParam());
|
||
return str;
|
||
}
|
||
|
||
// 查看当前合约的权限
|
||
public String showPermission() {
|
||
return JsonUtil.toJson(isOpen);
|
||
}
|
||
|
||
// 查看合约进程占用内存大小
|
||
public String getStorage() {
|
||
Runtime run = Runtime.getRuntime();
|
||
long mem = run.totalMemory() - run.freeMemory();
|
||
System.out.println("[ContractProcess] getStorage = " + ByteUtil.byteTo(mem));
|
||
return ByteUtil.byteTo(mem);
|
||
}
|
||
|
||
/*
|
||
* 将合约操作计入该合约的本地数据库中
|
||
*/
|
||
public void writeContractDB(Map<String, String> data) {
|
||
String path = dbPath;
|
||
if (path == null) {
|
||
// return "nopath";
|
||
return;
|
||
}
|
||
try {
|
||
String result = JsonUtil.toJson(data);
|
||
long hash = HashUtil.hashStr2Long(result);
|
||
logIndex.index(hash);
|
||
edion.put(String.valueOf(hash), result);
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
// return "failed";
|
||
}
|
||
// return "success";
|
||
}
|
||
|
||
@Override
|
||
protected void finalize() {
|
||
}
|
||
|
||
public String getDeclaredEvents() {
|
||
return JsonUtil.toJson(cn.events);
|
||
}
|
||
|
||
public String getAnnotations() {
|
||
return JsonUtil.toJson(cn.annotations);
|
||
}
|
||
|
||
public String getExportedFunctions() {
|
||
List<FunctionDesp> ret = new ArrayList<>();
|
||
for (FunctionNode fn : cn.getFunctions()) {
|
||
if (fn.isExport() && !fn.functionName.equals("onCreate")) {
|
||
function.add(fn.functionName);
|
||
FunctionDesp desp =
|
||
new FunctionDesp(fn.functionName, fn.annotations, fn.getRouteInfo(), fn.getJoinInfo(), fn.isView());
|
||
ret.add(desp);
|
||
}
|
||
}
|
||
return JsonUtil.toJson(ret);
|
||
}
|
||
|
||
public Contract getContract() {
|
||
return contract;
|
||
}
|
||
|
||
public String getPID() {
|
||
return this.pid;
|
||
}
|
||
|
||
public void setPID(String pid) {
|
||
this.pid = pid;
|
||
}
|
||
|
||
public String startAutoDump() {
|
||
String dumpPeriod = projectConfig.getDumpPeriod();
|
||
System.out.println(
|
||
"[ContractProcess] startAutoDump : "
|
||
+ cn.getContractName()
|
||
+ " period = "
|
||
+ dumpPeriod);
|
||
String status = "startAutoDump status 0";
|
||
if (null != dt) {
|
||
if (null == dumpPeriod || dumpPeriod.isEmpty()) {
|
||
dt.cancel();
|
||
status = "startAutoDump status 1";
|
||
} else {
|
||
dt.cancel();
|
||
Timer timer = new Timer();
|
||
dt = new DumpTask();
|
||
timer.schedule(dt, new Date(), Long.parseLong(dumpPeriod));
|
||
status = "startAutoDump status 2";
|
||
}
|
||
} else {
|
||
if (dumpPeriod != null && !dumpPeriod.equals("")) {
|
||
Timer timer = new Timer();
|
||
dt = new DumpTask();
|
||
timer.schedule(dt, new Date(), Long.parseLong(dumpPeriod));
|
||
status = "startAutoDump status 3";
|
||
}
|
||
}
|
||
|
||
LOGGER.debug("[ContractProcess] status : " + status);
|
||
return status;
|
||
}
|
||
|
||
public String getDir() {
|
||
return this.dir;
|
||
}
|
||
|
||
public void setDir(String s) {
|
||
this.dir = s + "/ADSPDir/" + contract.getID() + "/";
|
||
engine.syncUtil.setDir(dir);
|
||
}
|
||
|
||
public boolean isDebug() {
|
||
return contract.isDebug();
|
||
}
|
||
|
||
public String getCachedTransRecords(String startSeq) {
|
||
int start = Integer.parseInt(startSeq);
|
||
|
||
if (engine.syncUtil != null && engine.syncUtil.transRecordUtil != null) {
|
||
return engine.syncUtil.transRecordUtil.getCachedTransRecords(start);
|
||
}
|
||
|
||
return "";
|
||
}
|
||
|
||
public void clearSyncFiles(String arg) {
|
||
if (engine.syncUtil == null) {
|
||
LOGGER.debug("syncUtil is null, can not clear all sync files!");
|
||
return;
|
||
}
|
||
engine.syncUtil.clearAllFiles();
|
||
}
|
||
|
||
public String getStateful() {
|
||
return contract.getStateful() + "";
|
||
}
|
||
|
||
public void startSync() {
|
||
// engine.syncUtil.setContractID(contract.getID());
|
||
engine.syncUtil.setStartFlag(true);
|
||
}
|
||
|
||
public void setCRFile(String fileName) {
|
||
engine.syncUtil.setCRFile(fileName);
|
||
}
|
||
|
||
public void stopSync() {
|
||
engine.syncUtil.setStartFlag(false);
|
||
}
|
||
|
||
public String changeDebugFlag(Boolean b) {
|
||
contract.setDebug(b);
|
||
JavaScriptEntry.isDebug = b;
|
||
return "success";
|
||
}
|
||
|
||
public String parseYpkPermissions(String ypkPath) {
|
||
YJSCompiler compiler = new YJSCompiler();
|
||
try {
|
||
ContractZipBundle bundle = compiler.compile(new ZipFile(ypkPath));
|
||
ContractNode contractNode = bundle.mergeContractNode();
|
||
return JsonUtil.toJson(contractNode.getPermission());
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
}
|
||
return "[]";
|
||
}
|
||
|
||
public ProjectConfig getProjectConfig() {
|
||
return projectConfig;
|
||
}
|
||
|
||
public void setProjectConfig(String args) {
|
||
projectConfig = JsonUtil.fromJson(args, ProjectConfig.class);
|
||
String period = projectConfig.getDumpPeriod();
|
||
|
||
if (period != null && period.length() > 0) {
|
||
changeDumpPeriod(period);
|
||
}
|
||
// System.out.println("ContractProcessMask");
|
||
// JsonObject argsJS = JsonParser.parseString(args).getAsJsonObject();
|
||
// String contractID = "";
|
||
// String operation = "";
|
||
// JsonElement mask = JsonParser.parseString("");
|
||
// if (argsJS.has("contractID") && argsJS.has("operation") && argsJS.has("maskInfo"))
|
||
// {
|
||
// contractID = argsJS.get("contractID").getAsString();
|
||
// System.out.println(contractID);
|
||
// operation = argsJS.get("operation").getAsString();
|
||
// System.out.println(operation);
|
||
// mask = argsJS.get("maskInfo");
|
||
// System.out.println("mask" + mask);
|
||
// this.contract.setMask(operation, mask);
|
||
// }
|
||
}
|
||
|
||
public String getDependentContracts() {
|
||
return JsonUtil.toJson(cn.getDependentContracts());
|
||
}
|
||
|
||
public static class Logger extends PrintStream {
|
||
|
||
ContractProcess cp;
|
||
OutputStream out;
|
||
|
||
public Logger(OutputStream out, ContractProcess cp) {
|
||
super(out);
|
||
this.cp = cp;
|
||
this.out = out;
|
||
}
|
||
|
||
public Logger(OutputStream out) {
|
||
super(out);
|
||
cp = null;
|
||
this.out = out;
|
||
}
|
||
|
||
public Logger(PrintStream err) {
|
||
super(err);
|
||
this.out = null;
|
||
}
|
||
|
||
public ContractProcess getCp() {
|
||
return cp;
|
||
}
|
||
|
||
public void writeToDB(Map<String, String> data) {
|
||
if (cp != null) {
|
||
cp.writeContractDB(data);
|
||
}
|
||
}
|
||
// TODO we do not need outputTrace?
|
||
// public void outputTrace(String operation) {
|
||
// cp.writeContractDB(operation, this.toString());
|
||
// }
|
||
|
||
public String getOutputStr() {
|
||
return out.toString();
|
||
}
|
||
|
||
public void clean() {
|
||
if (out instanceof ByteArrayOutputStream) {
|
||
out = new ByteArrayOutputStream();
|
||
}
|
||
}
|
||
}
|
||
|
||
public static class Bean {
|
||
public String name;
|
||
public String value;
|
||
}
|
||
|
||
private class DumpTask extends TimerTask {
|
||
@Override
|
||
public void run() {
|
||
System.out.println(
|
||
"[ContractProcess DumpTask] auto dump period : "
|
||
+ projectConfig.getDumpPeriod());
|
||
File file1 = new File(dir);
|
||
File file2 = new File(file1.getParent());
|
||
String dir2 = file2.getParent() + "/memory/";
|
||
System.out.println("[ContractProcess] auto dump dir " + dir2);
|
||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd.HH_mm_ss"); // 设置日期格式
|
||
File f = new File(dir2 + cn.getContractName(), df.format(new Date()));
|
||
System.out.println("[ContractProcess] dump file " + f.getAbsolutePath());
|
||
|
||
File parent = f.getParentFile();
|
||
if (!parent.exists()) {
|
||
parent.mkdirs();
|
||
}
|
||
getMemoryDump(f.getAbsolutePath());
|
||
}
|
||
}
|
||
}
|