cm/src/main/java/org/bdware/sc/ContractManager.java
2021-09-26 12:50:12 +08:00

2329 lines
92 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package org.bdware.sc;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.prometheus.client.Counter;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.doip.core.model.handleRecord.DoHandleRecord;
import org.bdware.doip.core.utils.GlobalConfigurations;
import org.bdware.doip.endpoint.irpClient.GlobalIrpClient;
import org.bdware.sc.ContractResult.Status;
import org.bdware.sc.bean.*;
import org.bdware.sc.conn.OnHashCallback;
import org.bdware.sc.conn.ResultCallback;
import org.bdware.sc.conn.ServiceServer;
import org.bdware.sc.db.*;
import org.bdware.sc.event.EventBroker;
import org.bdware.sc.event.REvent;
import org.bdware.sc.event.REvent.REventSemantics;
import org.bdware.sc.handler.ManagerHandler;
import org.bdware.sc.node.*;
import org.bdware.sc.units.MultiContractMeta;
import org.bdware.sc.units.RespCache;
import org.bdware.sc.util.JsonUtil;
import org.bdware.sc.util.VersionUtil;
import org.hyperic.sigar.Mem;
import org.hyperic.sigar.ProcMem;
import org.hyperic.sigar.Sigar;
import org.zz.gmhelper.SM2KeyPair;
import org.zz.gmhelper.SM2Util;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
public class ContractManager {
public static final Object checkAndStartLock = new Object();
static final Counter contractCounter =
Counter.build()
.name("execute_contract_counter")
.help("contract execution status")
.register();
static final Counter oracleCounter =
Counter.build()
.name("execute_oracle_counter")
.help("oracle execution status")
.register();
static final Counter totalCounter =
Counter.build()
.name("execute_counter")
.help("contract and oracle execution status")
.register();
static final long memoryLimit = 100L * 1024L * 1024L;
private static final Logger LOGGER = LogManager.getLogger(ContractManager.class);
public static String yjsPath = null;
public static String dbPath;
public static String dir;
public static ContractManager instance;
public static Boolean reconnectFinish = false;
public static MultiIndexTimeRocksDBUtil logsDB;
public static ContractPort cPort;
public static boolean eventPersistenceEnabled = false;
public static ExecutorService threadPool =
new ThreadPoolExecutor(
8,
15,
60,
TimeUnit.SECONDS,
new SynchronousQueue<>());
public static ScheduledExecutorService scheduledThreadPool =
Executors.newScheduledThreadPool(10);
public static DoipServiceInfoConfigurer doipConfigurer;
public static int logStage = 0;
public static Sigar sigar = null; // 获取network等资源什么
static {
KeyValueDBUtil.setupCM();
KeyValueRocksDBUtil.setupCM();
TimeDBUtil.setupCM();
logsDB =
new MultiIndexTimeRocksDBUtil(
"./ContractManagerDB", CMTables.LocalContractLogDB.toString());
}
protected final EventBroker eventBroker;
public NodeCenterConn nodeCenterConn;
public MasterStub masterStub;
public ChainOpener chainOpener;
public ContractStatusRecorder statusRecorder;
public MultiContractRecorder multiContractRecorder;
public ProjectRecorder projectRecoder;
ManagerHandler handler;
ServiceServer server;
Map<String, RespCache> reqCache = new ConcurrentHashMap<>(); // key is requestID
private ContractClient analysisClient;
// private long expiredTime;
public ContractManager() {
instance = this;
handler = new ManagerHandler(this);
int startPort = cPort.getPortAndInc();
server = new ServiceServer(handler, startPort);
cPort.setCMPort(server.getPort());
if (server.getPort() != startPort) {
cPort.reSetPort(server.getPort() + 1);
}
eventBroker = new EventBroker();
statusRecorder = new ContractStatusRecorder("./ContractManagerDB");
multiContractRecorder = new MultiContractRecorder("./ContractManagerDB");
projectRecoder = new ProjectRecorder("./ContractManagerDB");
}
private static String convertToBytes(long traffic) {
String[] unit = new String[]{"B", "KB", "MB", "GB", "TB"};
double d = traffic;
int i;
for (i = 0; i < unit.length - 1; i++) {
if (d > 1024.0) {
d /= 1024.0;
} else {
break;
}
}
return String.format("%.2f %s", d, unit[i]);
}
// public static void updateContractHandleRecord(Contract c, ResultCallback resultCallback)
// throws Exception {
//
// DoHandleRecord contractHR = new DoHandleRecord(GlobalConfigurations.User_Handle,)
// resultCallback.onResult(contractDOI);
// }
// public static void updateContractHandleRecord(Contract c, String doi, ResultCallback
// resultCallback)
// throws Exception {
// // Dictionary<String, String> contractInfo = new Hashtable<String, String>();
// // contractInfo.put("id", c.getID());
// // contractInfo.put("publicKey", c.getPublicKey());
//
// HandleService hs = new HandleService(HandleServiceUtils.hrRegister);
// String contractDOI =
// hs.reregisterContract(doi, DOIPMainServer.repoIdentifier, c.getPublicKey());
//
// DigitalObject contractDO = queryContractDo(c, contractDOI);
// // DOAClient.getGlobalInstance().create(DOIPMainServer.repoIdentifier, contractDO);
// DoipClient doipClient =
// DoipClient.createByRepoUrlAndMsgFmt(
// DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName());
//
// // RepoHandleRecord repoHandleRecord =
// // DOAClient.getGlobalInstance().resolveRepo(DOIPMainServer.repoIdentifier);
//
// DoMessage response = doipClient.update(contractDO);
// if (response.parameters.response != DoResponse.Success) {
// doipClient.create(DOIPMainServer.repoIdentifier, contractDO);
// }
// resultCallback.onResult(contractDOI);
// }
//
// private static DigitalObject queryContractDo(Contract c, String contractDOI)
// throws IOException {
// DigitalObject cDo = new DigitalObject(contractDOI, DoType.Contract_ypk);
// Element e = new Element("contract", "ypk");
// e.setData(
// toByteArray(
// new ContractInstanceDO(
// c.getID(), c.getPublicKey(),
// fileToByteArray(c.getScriptStr()))));
// cDo.addElements(e);
// return cDo;
// }
//
// public static void registerMultiContractToDOA(Contract c, String doi) throws Exception {
// HandleService hs = new HandleService(HandleServiceUtils.hrRegister);
// hs.reregisterContract(doi, c.getNodeCenterRepoDOI(), c.getPublicKey());
//
// DigitalObject contractDO = new DigitalObject(doi, DoType.Contract_ypk);
// Element e = new Element("contract", "ypk");
// e.setData(
// toByteArray(
// new ContractInstanceDO(
// c.getID(), c.getPublicKey(),
// fileToByteArray(c.getScriptStr()))));
// contractDO.addElements(e);
// DoMessage response =
// DOAClient.getGlobalInstance().create(c.getNodeCenterRepoDOI(), contractDO);
//
// if (response.parameters.response != DoResponse.Success) {
// DOAClient.getGlobalInstance().update(contractDO);
// }
// /*
// DoipClient doipClient = DoipClient.createByRepoUrl(DOIPMainServer.repoUrl);
// DoMessage response = doipClient.create(contractDO);
// if (response.header.response != DoResponse.Success) {
// doipClient.update(contractDO);
// }
// */
// }
public static byte[] fileToByteArray(String filename) throws IOException {
File f = new File(filename);
if (!f.exists()) {
throw new FileNotFoundException(filename);
}
try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length())) {
BufferedInputStream in;
in = new BufferedInputStream(new FileInputStream(f));
int buf_size = 1024;
byte[] buffer = new byte[buf_size];
int len;
while (-1 != (len = in.read(buffer, 0, buf_size))) {
bos.write(buffer, 0, len);
}
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
public static byte[] toByteArray(Object obj) {
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return bytes;
}
public static Object toObject(byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
ois.close();
bis.close();
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
}
// ps是什么
public static Map<String, Map<String, String>> getContainerResourceInfoByPs() {
try {
Map<String, Map<String, String>> contractResourceInfo = new HashMap<>();
List<String> commands = new ArrayList<>();
commands.add("sh");
commands.add("-c");
commands.add("ps -aux | grep ContractProcess | grep java");
ProcessBuilder builder = new ProcessBuilder(commands);
Process process = builder.start();
Scanner sc = new Scanner(process.getInputStream());
String line;
while (sc.hasNext()) {
if ((line = sc.nextLine()).contains("aux")) {
continue;
}
LOGGER.debug("line: " + line);
String pid = null;
String cpu = null;
String mem = null;
String vsz = null;
String rss = null;
Scanner sc2 = new Scanner(new ByteArrayInputStream(line.getBytes()));
if (sc2.hasNext()) {
sc2.next();
if (sc2.hasNextInt()) {
pid = String.valueOf(sc2.nextInt());
}
if (sc2.hasNextFloat()) {
cpu = sc2.nextFloat() + "%";
}
if (sc2.hasNextFloat()) {
mem = sc2.nextFloat() + "%";
}
if (sc2.hasNextInt()) {
vsz = sc2.nextInt() + " Bytes";
}
if (sc2.hasNextInt()) {
rss = sc2.nextInt() + " Bytes";
}
}
fillContractResourceInfo(contractResourceInfo, pid, rss, cpu, mem, sc2);
}
return contractResourceInfo;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
// By ps 和 by top
public static Map<String, Map<String, String>> getContainerResourceInfoByTop() {
try {
Map<String, Map<String, String>> contractResourceInfo = new HashMap<>();
Process process = Runtime.getRuntime().exec("top -b -n 1");
InputStreamReader ir = new InputStreamReader(process.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
String line;
while ((line = input.readLine()) != null) {
if (!line.contains("java")) {
continue;
}
// System.out.println(line);
String pid = null;
String res = null;
String cpu = null;
String mem = null;
Scanner sc2 = new Scanner(new ByteArrayInputStream(line.getBytes()));
if (sc2.hasNext()) {
if (sc2.hasNextInt()) {
pid = String.valueOf(sc2.nextInt());
}
sc2.next();
sc2.next();
sc2.next();
sc2.next();
if (sc2.hasNextInt()) {
res = sc2.nextInt() + " Bytes";
}
sc2.next();
sc2.next();
if (sc2.hasNextFloat()) {
cpu = sc2.nextFloat() + "%";
}
if (sc2.hasNextFloat()) {
mem = sc2.nextFloat() + "%";
}
}
fillContractResourceInfo(contractResourceInfo, pid, res, cpu, mem, sc2);
}
return contractResourceInfo;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static void fillContractResourceInfo(
Map<String, Map<String, String>> contractResourceInfo,
String pid,
String res,
String cpu,
String mem,
Scanner sc2) {
sc2.close();
Map<String, String> tmp = new HashMap<>();
tmp.put("%CPU", cpu);
tmp.put("%MEM", mem);
tmp.put("MEM", res);
contractResourceInfo.put(pid, tmp);
}
public static boolean checkNodeManager(String owner) {
String nodeManagerPubkey =
KeyValueDBUtil.instance.getValue(CMTables.ConfigDB.toString(), "__NodeManager__");
boolean isNodeManager = false;
if (null != nodeManagerPubkey && nodeManagerPubkey.length() > 0) {
isNodeManager = (nodeManagerPubkey.equals(owner));
}
return isNodeManager;
}
public static void checkPointToLedger(
OnHashCallback cb, String contractID, String data, String requestID) {
boolean isMaster = instance.getContractIsMaster(contractID);
if (!isMaster) {
LOGGER.info("非合约 " + contractID + "的master无需承担checkPoint上链任务!");
return;
}
instance.chainOpener.writeToChain(cb, contractID, "checkPoint", data, requestID, "");
}
public static String getContractMd5(String scriptOrPath, Contract c) {
try {
if (c.getScriptStr().startsWith("/")) {
String md5 = DigestUtils.md5Hex(new FileInputStream(scriptOrPath));
LOGGER.debug("starting contract: ypk.md5=" + md5);
if (c.getOwner() != null) {
md5 = DigestUtils.md5Hex(md5 + c.getOwner());
}
LOGGER.debug("starting contract: ypk.md5=" + md5 + " owner.md5=" + c.getOwner());
return "bundle_" + md5;
} else {
String md5 = DigestUtils.md5Hex(c.getScriptStr());
if (c.getOwner() != null) md5 = DigestUtils.md5Hex(md5 + c.getOwner());
return "script_" + md5;
}
} catch (Exception e) {
e.printStackTrace();
return "tempr_" + new Random().nextLong();
}
}
public void initAnalysisClient() {
Contract c = new Contract();
c.setType(ContractExecType.Sole);
SM2KeyPair pair = SM2Util.generateSM2KeyPair();
c.setOwner(pair.getPublicKeyStr());
c.setScript("contract analysis_client{}");
analysisClient = new ContractClient(c);
analysisClient.startProcess(System.out);
}
public String getContractIDByName(String name) {
ContractMeta meta = statusRecorder.getContractMeta(name);
if (meta != null) return meta.id;
return null;
}
public String getContractNameByID(String id) {
ContractMeta meta = statusRecorder.getContractMeta(id);
if (meta != null) return meta.name;
return null;
}
// public void setExpiredTime(long time) {
// expiredTime = time;
// }
public void reconnectContractProcess() {
RecoverMechTimeRecorder.startReconnectCP = System.currentTimeMillis();
LOGGER.info("reconnectContractProcess");
cPort.visitReconnectPortRange(statusRecorder.getVisitor());
statusRecorder.reSyncStatusAtStart();
synchronized (checkAndStartLock) {
reconnectFinish = true;
LOGGER.info("checkAndStartLock is set to true");
checkAndStartLock.notifyAll();
RecoverMechTimeRecorder.reconnectCPFinish = System.currentTimeMillis();
}
}
public ContractClient getContractClientByDoi(String doi) {
ContractMeta meta = statusRecorder.getContractMeta(doi);
return statusRecorder.getContractClient(meta.id);
}
public String startContractAndRedirectWithDebug(Contract c) {
return startContractAndRedirect(c, System.out, null, true);
}
public String startContractAndRedirect(Contract c, PrintStream ps) {
return startContractAndRedirect(c, ps, null, false);
}
public String getContractStateful(String contractID) {
ContractClient cc = getClient(contractID);
if (null == cc) {
return "true";
}
return cc.get.syncGet("", "getStateful", "");
}
public String getDumpPeriod(String contractName) {
ContractClient client = getByName(contractName);
if (client == null) {
return "failed";
}
String result = client.get.syncGet("", "getDumpPeriod", "a");
ContractMeta meta = client.contractMeta;
addLocalContractLog(
"getDumpPeriod", meta.contract.getID(), meta.name, meta.contract.getOwner());
if (!"failed".equals(result)) {
return result;
}
return "failed";
}
// load latest memory after startContract
public void initLoadMemory(ContractClient client) {
if (client == null) {
LOGGER.debug("contract process not found");
return;
}
// init annotation
String ff = client.get.syncGet("", "getMemorySet", "");
LOGGER.debug("[init load] memorySet : " + ff);
if (null == ff || ff.isEmpty()) {
LOGGER.debug("do not need load when start, finished");
return;
}
// String[] strs = ff.split(";");
if (!ff.contains("init")) {
LOGGER.debug("do not need load when start,finished");
return;
}
String path = findNewestMemory(client.getContractName());
if (path != null) {
String result = loadMemory(client, path);
if (result.equals("success")) {
LOGGER.debug("init load memory finished");
} else {
LOGGER.debug("init load memory failed");
}
} else {
LOGGER.debug("no memory file,init load memory failed");
}
}
public String findNewestMemory(String contractName) {
File f = new File(dir + "/memory/" + contractName);
if (f.exists() && f.isDirectory()) {
String path = null;
for (File subFile : Objects.requireNonNull(f.listFiles())) {
if (path == null) path = subFile.getName();
else if (path.compareTo(subFile.getName()) < 0) {
path = subFile.getName();
}
}
if (path == null) {
LOGGER.debug("no memory file,init load memory finished");
return null;
}
path = f.getAbsolutePath() + "/" + path;
return path;
}
return null;
}
public String changeDumpPeriod(String contractName, String dumpPeriod) {
ContractResult r;
ContractClient client = getByName(contractName);
ProjectConfig config = projectRecoder.getProjectConfig(contractName);
config.setDumpPeriod(dumpPeriod);
if (null == client) {
r = new ContractResult(Status.Error, new JsonPrimitive("contract process not found"));
return JsonUtil.toJson(r);
}
loadProjectConfig(client);
ContractMeta meta = client.contractMeta;
addLocalContractLog(
"changeDumpPeriod", meta.contract.getID(), meta.name, meta.contract.getOwner());
r = new ContractResult(Status.Success, new JsonPrimitive("change dump period finished"));
return JsonUtil.toJson(r);
}
// public String resumeStartContractAndRedirect(Contract c, PrintStream ps, String alias) {
// long freeMemory = getFreeMemory();
// if (freeMemory < memoryLimit) {
// ContractResult r =
// new ContractResult(
// Status.Error, new JsonPrimitive("insufficient memory:" +
// freeMemory));
// return JsonUtil.toJson(r);
// }
// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
// Date date = new Date();
// try {
// date = format.parse("2022-03-31");
// } catch (ParseException e) {
// e.printStackTrace();
// }
// if (System.currentTimeMillis() > date.getTime()) {
// ContractResult ret =
// new ContractResult(Status.Error, new JsonPrimitive("Licence Time
// Expired"));
// return JsonUtil.toJson(ret);
// }
// SM2KeyPair sm2Key = SM2Util.generateSM2KeyPair(null);
// ContractResult r;
// try {
// if (c.getScriptStr().startsWith("/")) {
// c.startInfo.isYPK = true;
// String[] str = c.getScriptStr().split("/");
// String tmp = new File(dir + "/publicCompiled/ypkName").getAbsolutePath();
// String[] str2 = tmp.split("/");
// if (str.length > str2.length) {
// c.startInfo.isPrivate = true;
// c.startInfo.pubKeyPath = str[str.length - 2];
// }
// c.startInfo.ypkName = str[str.length - 1];
// LOGGER.info("print Contract Start Info");
// c.startInfo.print();
// }
// if (null == c.getKey()) {
// String key = getContractMd5(c);
// String privateKeyStr =
// KeyValueDBUtil.instance.getValue(CMTables.ContractInfo.toString(),
// key);
// if (privateKeyStr == null || privateKeyStr.length() == 0) {
// privateKeyStr = SM2Util.generateSM2KeyPair().toJson();
// KeyValueDBUtil.instance.setValue(
// CMTables.ContractInfo.toString(), key, privateKeyStr);
// }
// sm2Key = SM2KeyPair.fromJson(privateKeyStr);
// c.setKey(sm2Key.getPrivateKey().toString(16));
// c.setPublicKey(sm2Key.getPublicKeyStr());
// }
// int contractID;
// if (null != c.getHash() && !c.getHash().equals("")) {
// contractID = Integer.parseInt(c.getHash());
// } else {
// contractID = c.getPublicKey().hashCode();
// }
//
// if (c.getID() == null) c.setID(contractID));
// if (null == c.getOwner()) {
// c.setOwner(sm2Key.getPublicKeyStr());
// }
// LOGGER.debug("contract pubKey: " + c.getPublicKey());
// // 合约启动时读取Manifest文件设置合约DOI
// setContractDOI(c);
// setContractStateful(c);
// ContractClient client = new ContractClient(c);
// String ret;
// String conflictCheck;
// addLocalContractLog("startContract", c.getID(), client.contractName,
// c.getOwner());
// switch (c.getType()) {
// case RequestOnce:
// case ResponseOnce:
// LOGGER.debug("[Start Unsync Contract]");
// ret = client.startProcess(ps);
// conflictCheck = resumeCheckConflict(c, client, ret);
// if (null != conflictCheck) {
// return conflictCheck;
// }
//
// String tempTime2 =
// KeyValueDBUtil.instance.getValue(
// CMTables.ContractInfo.toString(),
// client.contractName + "-Times");
// String tempTraffic2 =
// KeyValueDBUtil.instance.getValue(
// CMTables.ContractInfo.toString(),
// client.contractName + "-Traffic");
// if (tempTime2 != null && !tempTime2.equals("")) {
// client.times = Long.parseLong(tempTime2);
// }
// if (tempTraffic2 != null && !tempTraffic2.equals("")) {
// client.traffic = Long.parseLong(tempTraffic2);
// }
// client.traffic += ret.length();
//
// client.get.syncGet("", "setDir", ContractManager.dir);
// initLoadMemory(c.getID());
// ContractStatusRecorder.createContract(c, client);
//
// return ret;
// case RequestAllResponseAll:
// case RequestAllResponseFirst:
// case RequestAllResponseHalf:
// case Sole:
// ret = client.startProcess(ps);
// conflictCheck = checkConflict(c, client, ret);
// if (null != conflictCheck) {
// return conflictCheck;
// }
//
// String tempTime =
// KeyValueDBUtil.instance.getValue(
// CMTables.ContractInfo.toString(),
// client.contractName + "-Times");
// String tempTraffic =
// KeyValueDBUtil.instance.getValue(
// CMTables.ContractInfo.toString(),
// client.contractName + "-Traffic");
// if (tempTime != null && !tempTime.equals("")) {
// client.times = Long.parseLong(tempTime);
// }
// if (tempTraffic != null && !tempTraffic.equals("")) {
// client.traffic = Long.parseLong(tempTraffic);
// }
// client.traffic += ret.length();
//
// if (alias != null) {
// client.setIdentifier(alias);
// }
// if (c.getDoipFlag() && !c.getDOI().equals("registerFailed")) {
// client.setIdentifier(c.getDOI());
// }
// client.get.syncGet("", "setDir", ContractManager.dir);
// initLoadMemory(c.getID());
// ContractStatusRecorder.updateContract(c, client);
// return ret;
// default:
// return "todo";
// }
// } catch (Exception e) {
// e.printStackTrace();
// r = new ContractResult(Status.Error, new JsonPrimitive("exception occurs"));
// return JsonUtil.toJson(r);
// }
// }
//
// private String resumeCheckConflict(Contract c, ContractClient client, String ret) {
// if (JsonUtil.fromJson(ret, ContractResult.class).status == Status.Success) {
// if (findConflictOfName(client.getContractName())) {
// ContractManager.instance.invokeContractSuicide(client);
// ContractResult r =
// new ContractResult(
// Status.Error, new JsonPrimitive("Duplicate contract name."));
// return JsonUtil.toJson(r);
// }
// ContractStatusRecorder.updateContractClient(c.getID(), client);
// }
// return null;
// }
//
// public String resumeStartContract(Contract c) {
// return resumeStartContractAndRedirect(c, System.out, null);
// }
public long getFreeMemory() {
try {
if (null == sigar) {
sigar = new Sigar();
}
Mem mem = sigar.getMem();
LOGGER.debug("[free memory] " + mem.getFree() + " " + mem.getActualFree());
return mem.getFree();
} catch (Throwable e) {
e.printStackTrace(System.err);
e.printStackTrace();
}
return memoryLimit + 1;
}
// private void hangUpKillContract(String contractID) {
// ContractClient client = ContractStatusRecorder.getContractClientById(contractID);
// if (client != null) {
// try {
// String ff = client.get.syncGet("", "getMemorySet", "");
// LOGGER.info("[killContract] memorySet : " + ff);
// if (ff != null) {
// if (ff.contains("kill")) {
// LOGGER.info("need dump when stop");
// String contractName = client.getContractName();
// SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd.HH:mm:ss");
// File f = new File(dir + "/memory/" + contractName, df.format(new
// Date()));
// dumpContract(contractName, f.getAbsolutePath());
// }
// }
// String contractName = client.contractName;
// ContractStatusRecorder.id2ContractClient.remove(contractID);
// name2Contract.remove(contractName);
// doi2Contract.remove(client.getContractDOI());
// String str = client.getIdentifier();
// if (str != null && !str.equals("null")) {
// name2Contract.remove(str, client);
// }
// ContractManager.instance.invokeContractSuicide(client);
// eventBroker.unSub(contractName, null);
//
// LOGGER.info(
// String.format(
// "killContract: %s id--> %s result: %s",
// client.contractName, contractID, r));
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// }
public void addLocalContractLog(String action, ContractClient client) {
ContractMeta meta = client.contractMeta;
addLocalContractLog(action, meta.contract.getID(), meta.name, meta.contract.getOwner());
}
public String startContractAndRedirect(Contract c, PrintStream ps, String alias, boolean isDebug) {
long freeMemory = getFreeMemory();
if (freeMemory < memoryLimit || statusRecorder.runningProcess.size() > 8) {
statusRecorder.hangLeastUsedContractProcess();
// ContractResult r =
// new ContractResult(
// Status.Error, new JsonPrimitive("insufficient memory:" + freeMemory));
// return JsonUtil.toJson(r);
}
// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
ContractResult r;
try {
if (c.getScriptStr().startsWith("/")) {
c.startInfo.isYPK = true;
String[] str = c.getScriptStr().split("/");
String tmp = new File(dir + "/publicCompiled/ypkName").getAbsolutePath();
String[] str2 = tmp.split("/");
if (str.length > str2.length) {
c.startInfo.isPrivate = true;
c.startInfo.pubKeyPath = str[str.length - 2];
}
c.startInfo.ypkName = str[str.length - 1];
LOGGER.info(c.startInfo);
}
allocateKeyIfNotExists(c);
if (null == c.getOwner()) {
c.setOwner(c.getPublicKey());
}
LOGGER.debug("contract pubKey: " + c.getPublicKey());
// 合约启动时读取Manifest文件设置合约DOI
setContractDOI(c);
setContractStateful(c);
// if (c.getDoipFlag()) {
// // 合约部署时更新合约HandleRecord
// long tmpStart = System.currentTimeMillis();
// try {
// if (c.getDOI() == null || c.getDOI().equals("")) {
// updateContractHandleRecord( // 创建DO
// c,
// new ResultCallback() {
// @Override
// public void onResult(String str) {
// c.setDOI(str);
// // c.setID(str);
// LOGGER.debug("contract DOI: " + c.getDOI());
// }
// });
// } else {
// if (findConflictOfDOI(c.getDOI())) {
// r = new ContractResult(Status.Error, "Duplicate contract
// DOI.");
// return JsonUtil.toJson(r);
// }
// }
// } catch (Exception e) {
// ByteArrayOutputStream bo = new ByteArrayOutputStream();
// e.printStackTrace(new PrintStream(bo));
// c.setDOI("registerFailed");
// }
// LOGGER.info("DOIP executeTime: " + (System.currentTimeMillis() -
// tmpStart));
// } else c.setDOI("registerDisabled");
// if (contracts.containsKey(c.getID())) {
// r = new ContractResult(Status.Error, "contract existed");
// return JsonUtil.toJson(r);
// }
ContractClient client = new ContractClient(c);
client.isDebug = isDebug;
String ret;
String conflictCheck;
addLocalContractLog("startContract", c.getID(), client.contractMeta.name, c.getOwner());
switch (c.getType()) {
case RequestOnce:
case ResponseOnce:
LOGGER.debug("[Start Async Contract]");
ret = client.startProcess(ps);
conflictCheck = checkConflict(c, client, ret);
if (null != conflictCheck) {
return conflictCheck;
}
client.traffic += ret.length();
// TODO @ZYX
client.get.syncGet("", "setDir", ContractManager.dir);
initLoadMemory(client);
statusRecorder.createContract(client);
loadProjectConfig(client);
return ret;
case RequestAllResponseAll:
case RequestAllResponseFirst:
case RequestAllResponseHalf:
case Shading:
case Sole:
ret = client.startProcess(ps);
conflictCheck = checkConflict(c, client, ret);
if (null != conflictCheck) {
return conflictCheck;
}
client.traffic += ret.length();
// TODO @ZYX
// updateContractInfo(client);
if (alias != null) {
client.setIdentifier(alias);
}
if (c.getDoipFlag() && !c.getDOI().equals("registerFailed")) {
client.setIdentifier(c.getDOI());
}
// if (BDOAHandler.cm != null) {
// BDOAHandler.cm.name2Contract = name2Contract;
// }
client.get.syncGet("", "setDir", ContractManager.dir);
// Signature sig = sm2.sign(ret.getBytes(),sm2Key.getPrivateKey());
// ContractResult result = JsonUtil.fromJson(ret, ContractResult.class);
// result.pubkey = sm2Key.getPublicKeyStr();
// result.result =
// sm2.sign(result.result.getBytes(),sm2Key.getPrivateKey()).toString();
// return JsonUtil.toJson(result);
initLoadMemory(client);
statusRecorder.createContract(client);
loadProjectConfig(client);
return ret;
default:
return "todo";
}
} catch (Exception e) {
e.printStackTrace();
r = new ContractResult(Status.Error, new JsonPrimitive("exception occurs"));
return JsonUtil.toJson(r);
}
}
public void loadProjectConfig(ContractClient client) {
// a
// from DB
ProjectConfig config = projectRecoder.getProjectConfig(client.getContractID());
LOGGER.debug("zz");
String str = client.contractMeta.contract.getScriptStr();
/*if(config!=null){
System.out.println("not NULL");
client.setProjectConfig(JsonUtil.toJson(config));
return;
}*/
// TODO
loadMaskConfig(config, str);
loadMockConfig(config, str);
client.setProjectConfig(JsonUtil.toJson(config));
}
private void loadMockConfig(ProjectConfig config, String str) {
MockConfig mockDB = config.getMockConfig();
MockConfig mockYPK = YJSPacker.getConfig(str, "/mockConfig.json", MockConfig.class);
if (mockYPK != null) {
if (mockDB == null) {
config.setMockConfig(mockYPK);
} else {
int mockVersion = VersionUtil.compareVersion(mockDB.version, mockYPK.version);
if (mockVersion == -1) {
// YPK
config.setMockConfig(mockYPK);
// client.setProjectConfig(JsonUtil.toJson(config));
} //else {
// bubian
//}
}
}
}
private void loadMaskConfig(ProjectConfig config, String str) {
//从ypk当中检查是否更新若YPK中没有配置文件则不更新
//若有且版本号更大,则更新
MaskConfig maskYPK = YJSPacker.getConfig(str, "/maskConfig.json", MaskConfig.class);
if (maskYPK != null) {
//System.out.println("YPKConf" + maskYPK.config);
MaskConfig maskDB = config.getMaskConfig();
if (maskDB == null) {
config.setMaskConfig(maskYPK);
//System.out.println("maskNull" + config.getMaskConfig().config);
} else {
int maskVersion = VersionUtil.compareVersion(maskDB.version, maskYPK.version);
if (maskVersion == -1) {
// YPK版本更新
config.setMaskConfig(maskYPK);
//System.out.println("mask-1" + config.getMaskConfig().config);
// client.setProjectConfig(JsonUtil.toJson(config));
}
}
}
}
public void allocateKeyIfNotExists(Contract c) {
if (null == c.getKey()) {
String key = getContractMd5(c.getScriptStr(), c);
String privateKeyStr =
KeyValueDBUtil.instance.getValue(CMTables.ContractInfo.toString(), key);
if (privateKeyStr == null || privateKeyStr.length() == 0) {
privateKeyStr = SM2Util.generateSM2KeyPair().toJson();
KeyValueDBUtil.instance.setValue(
CMTables.ContractInfo.toString(), key, privateKeyStr);
}
SM2KeyPair sm2Key = SM2KeyPair.fromJson(privateKeyStr);
c.setKey(sm2Key.getPrivateKey().toString(16));
c.setPublicKey(sm2Key.getPublicKeyStr());
c.setID(String.valueOf(c.getPublicKey().hashCode()));
}
}
private String checkConflict(Contract c, ContractClient client, String ret) {
if (JsonUtil.fromJson(ret, ContractResult.class).status == Status.Success) {
if (findConflictOfName(client.getContractName())) {
invokeContractSuicide(client);
ContractResult r =
new ContractResult(
Status.Error, new JsonPrimitive("Duplicate contract name."));
return JsonUtil.toJson(r);
}
}
return null;
}
private void setContractDOI(Contract c) {
if (DoConfig.callContractUsingDOI) {
ContractManifest cm = YJSPacker.getManifest(c.getScriptStr());
if (cm != null && cm.doi != null) {
if (!cm.doi.equals("")
&& !cm.doi.equals("null")
&& c.getType() == ContractExecType.Sole) {
c.setDOI(cm.doi);
c.setBuildTime(cm.buildTime);
c.setDoipFlag(true);
DoHandleRecord dohr =
new DoHandleRecord(
GlobalConfigurations.User_Handle,
GlobalConfigurations.DoipServiceID);
dohr.handle = cm.doi;
threadPool.execute(
() -> {
try {
GlobalIrpClient.getGlobalClient().reRegister(dohr);
} catch (Exception e) {
LOGGER.warn("unable to connect LHS: " + e.getMessage());
}
});
}
}
} else {
c.setDoipFlag(false);
}
}
private void setContractStateful(Contract c) {
ContractManifest cm = YJSPacker.getManifest(c.getScriptStr());
if (cm != null && cm.stateful != null && cm.stateful.equals("false")) {
c.setStateful(false);
}
}
public String startContract(Contract c) {
return startContractAndRedirect(c, System.out);
}
public String queryDEPort(String contractID) {
ContractClient client = getClient(contractID);
if (null == client) {
return "no such contract:" + contractID;
} else {
return client.get.syncGet("", "queryDEPort", "");
}
}
public String addDEMember(String contractID, String hostAndPort) {
ContractClient client = getClient(contractID);
if (null == client) {
return "no such contract:" + contractID;
} else {
return client.get.syncGet("", "addDEMember", hostAndPort);
}
}
public String getScriptStrByID(String cid) {
ContractClient client = getClient(cid);
if (null != client) {
return client.contractMeta.contract.getScriptStr();
} else {
return "contract " + cid + " not exists";
}
}
// TODO
public String requestContract(ContractRequest c) {
return "todo";
}
public synchronized ContractClient getClient(String idOrName) {
ContractClient client = statusRecorder.getContractClient(idOrName);
return client;
}
public void clearCache() {
final long time = System.currentTimeMillis() - 30000L;
// LOGGER.info("try to clear cache, clear 0");
/* reqCache.entrySet()
.removeIf(
entry -> {
RespCache cache = entry.getValue();
if (cache == null) return true;
if (cache.count < 0) return true;
return cache.time < time;
});
*/
}
synchronized RespCache getCache(String requestID) {
if (null != requestID && requestID.endsWith("_mul")) {
RespCache cache = reqCache.get(requestID);
if (null != cache) {
return cache;
} else {
LOGGER.debug("create cache:" + requestID);
RespCache resp = new RespCache();
try {
resp.count =
Integer.parseInt(
requestID
.replaceFirst("[^_]*_", "")
.replaceAll("_.*$", ""));
} catch (Exception e) {
resp.count = 2;
}
// TODO 这个部分肯定要改哦。
// A是requestAll模式的合约
// B是授受调用者的因此B需要检查AB不能直接返回需要"等待一半以上的commit?并且存下参数"
reqCache.put(requestID, resp);
LOGGER.debug("put into cache:" + requestID);
return resp;
}
}
return null;
}
public void executeLocallyAsync(ContractRequest c, final ResultCallback r, OnHashCallback cb) {
ContractResult cr;
String requestID = c.getRequestID();
// 9000
if (null == c.getContractID()) {
LOGGER.info("合约Name转为ID error!");
cr =
new ContractResult(
Status.Error,
new JsonPrimitive(
c.getContractID() + " Contract not Exists, CMLocallyAsync!"));
r.onResult(JsonUtil.toJson(cr));
return;
}
// 在这里进行判断是否唤醒挂起的合约
statusRecorder.ensureRunning(c);
final ContractClient client = getClient(c.getContractID());
if (null == client) {
cr =
new ContractResult(
Status.Error,
new JsonPrimitive(
c.getContractID() + " Contract not Exists, CMLocallyAsync!"));
r.onResult(JsonUtil.toJson(cr));
return;
}
long start = System.currentTimeMillis();
// 9000
final RespCache cache = getCache(requestID);
// TODO 从LHS中获取该请求的公钥对应的运行节点的公钥列表
// 等待1/2以上的运行节点公钥列表到达时才进行下一步。
if (null != cache) {
clearCache();
if (cache.waitForHalf()) {
synchronized (cache) {
if (cache.val != null) {
LOGGER.info("[Hit Cache] " + requestID);
r.onResult(cache.val);
} else {
executeInternalAsync(
client,
c,
new ResultCallback() {
@Override
public void onResult(String str) {
cache.time = start;
cache.val = str;
r.onResult(cache.val);
cache.notifyAllWaiter();
}
},
cb);
}
return;
}
} else {
ContractResult re =
new ContractResult(
Status.Error,
new JsonPrimitive("Timeout due to insufficient requester"));
r.onResult(JsonUtil.toJson(re));
return;
}
}
// 9000
executeInternalAsync(client, c, r, cb);
}
public String executeLocally(ContractRequest c, OnHashCallback cb) {
long start = System.currentTimeMillis();
// LOGGER.info(
// "[ContractManager] executeLocally : ContractRequest.requestID="
// + c.getRequestID()
// + " tid:"
// + Thread.currentThread().getId());
String requestID = c.getRequestID();
if (c.getContractID() == null) {
LOGGER.info("合约Name转为ID error!");
ContractResult cr =
new ContractResult(
Status.Error,
new JsonPrimitive(
c.getContractID() + " Contract not Exists, CMLocally!"));
return JsonUtil.toJson(cr);
}
// TODO synchronized according to reqID?
ContractResult cr2;
ContractClient client = getClient(c.getContractID());
if (client == null) {
cr2 =
new ContractResult(
Status.Error,
new JsonPrimitive(
c.getContractID() + " Contract not Exists, CMLocally!"));
return JsonUtil.toJson(cr2);
}
// LOGGER.info("[ContractManager] executeLocally : requestID=" + requestID);
RespCache cache = getCache(requestID);
// TODO 从LHS中获取该请求的公钥对应的运行节点的公钥列表
// 等待1/2以上的运行节点公钥列表到达时才进行下一步。
if (null != cache) {
if (cache.waitForHalf()) {
synchronized (cache) {
if (cache.val != null) {
LOGGER.info("[Hit Cache] " + requestID);
return cache.val;
} else {
String result = executeInternal(client, c, cb);
cache.time = start;
cache.val = result;
cache.notifyAllWaiter();
return result;
}
}
} else {
ContractResult re =
new ContractResult(
Status.Error,
new JsonPrimitive("Timeout due to insufficient requester"));
return JsonUtil.toJson(re);
}
}
// LOGGER.info("cache is null");
clearCache();
return executeInternal(client, c, cb);
}
private void executeInternalAsync(
ContractClient client, ContractRequest request, ResultCallback rcb, OnHashCallback cb) {
ContractResult cr;
long start = System.currentTimeMillis();
// 9000
if (client.contractMeta.sigRequired) {
if (!request.verifySignature()) {
cr = new ContractResult(Status.Error, new JsonPrimitive("sign verified failed"));
rcb.onResult(JsonUtil.toJson(cr));
return;
}
}
client.times++;
client.contractStatus = ContractStatus.Executing;
ResultCallback acb;
// TODO acb bu dei jin
acb =
new ResultCallback() {
@Override
public void onResult(String result) {
client.traffic += result.length();
client.contractStatus = ContractStatus.Executed;
String finalRet = result;
if (client.getContractCopies() == 1) {
finalRet =
extractEventsFromContractResult(
cb, result, client, request, start);
}
rcb.onResult(finalRet);
if (finalRet.length() == result.length()) {
chainOpener.writeContractResultToLocalAndLedger(
finalRet,
client,
request,
cb,
start,
System.currentTimeMillis() - start);
}
if (client.contractMeta.getYjsType()==YjsType.Oracle){
oracleCounter.inc();
}else {
contractCounter.inc();
}
totalCounter.inc();
}
};
// if (ignoreLog) {
// rcb.onResult(
//
// "{\"needSeq\":false,\"seq\":0,\"status\":\"Success!!!!\",\"result\":\"world\","+
// "\"isInsnLimit\":false,\"totalGas\":0,\"executionGas\":0,\"extraGas\":0,\"size\":0}");
// return;
// }
client.get.asyncGet("", "executeContract", JsonUtil.toJson(request), acb);
}
private String executeInternal(
ContractClient client, ContractRequest request, OnHashCallback ocb) {
// LOGGER.info("ContractManager executeInternal : ");
ContractResult cr;
long start = System.currentTimeMillis();
if (client.contractMeta.sigRequired) {
if (!request.verifySignature()) {
cr = new ContractResult(Status.Error, new JsonPrimitive("sign verified failed"));
return JsonUtil.toJson(cr);
}
}
client.times++;
// 将合约状态改为“Executing”
client.contractStatus = ContractStatus.Executing;
// 占用一个线程的资源等待如果现在处于recovering状态ContractRequest放入队列直接返回recovering结果
String result = client.get.syncGet("", "executeContract", JsonUtil.toJson(request));
LOGGER.debug(result);
client.traffic += result.length();
String finalRet = result;
if (client.getContractCopies() == 1) {
finalRet = extractEventsFromContractResult(ocb, result, client, request, start);
}
if (finalRet.length() == result.length()) {
chainOpener.writeContractResultToLocalAndLedger(
result, client, request, ocb, start, System.currentTimeMillis() - start);
}
contractCounter.inc();
return result;
}
/**
* event related
*
* @author Kaidong Wu
*/
public String extractEventsFromContractResult(
OnHashCallback ocb,
String result,
ContractClient client,
ContractRequest request,
long startTime) {
String ret = result;
try {
ContractResult cr = JsonUtil.fromJson(result, ContractResult.class);
if (null != cr.events && !cr.events.isEmpty()) {
List<REvent> msgList = cr.events;
cr.events = null;
ret = JsonUtil.toJson(cr);
chainOpener.writeContractResultToLocalAndLedger(
ret,
client,
request,
(reqID, hashStr) -> {
if (eventPersistenceEnabled) {
msgList.forEach(
msg -> {
msg.setTxHash(hashStr);
msg.doSignature(
client.getPubkey(), client.getContractKey());
eventBroker.handle(msg);
});
}
if (null != ocb) {
ocb.publishHash(reqID, hashStr);
}
},
startTime,
System.currentTimeMillis() - startTime);
if (!eventPersistenceEnabled) {
threadPool.submit(
() ->
msgList.forEach(
e -> {
e.doSignature(
client.getPubkey(),
client.contractMeta.contract.getKey());
eventBroker.handle(e);
}));
}
}
} catch (Exception ignored) {
}
return ret;
}
public int countEvents() {
return eventBroker.countEvents();
}
public void removeContract(String contractID) {
statusRecorder.killContract(contractID);
}
public boolean hasPID(int pid) {
return statusRecorder.hasPID(pid);
}
public String execute(ContractRequest c, OnHashCallback cb) {
// return masterStub.executeGlobally(c, cb);
StrCollector resultCallback = new StrCollector();
executeContractInternal(c, resultCallback, cb);
resultCallback.waitForResult();
return resultCallback.strRet;
}
public void executeContractInternal(
ContractRequest cr, final ResultCallback rcb, final OnHashCallback hcb) {
LOGGER.debug(JsonUtil.toJson(cr));
ContractMeta meta = statusRecorder.getContractMeta(cr.getContractID());
MultiContractMeta multiMeta =
multiContractRecorder.getMultiContractMeta(cr.getContractID());
if (null == meta || meta.status == ContractStatusEnum.KILLED) {
executeContractOnOtherNodes(cr, rcb);
} else {
statusRecorder.ensureRunning(cr);
ContractClient client = statusRecorder.getContractClient(meta.id);
switch (client.getContractType()) {
case Sole:
executeLocallyAsync(cr, rcb, hcb);
return;
case RequestOnce:
case ResponseOnce:
case Shading:
masterStub.executeByMaster(client, rcb, cr);
break;
case RequestAllResponseAll:
case RequestAllResponseFirst:
case RequestAllResponseHalf:
if (multiMeta != null && multiMeta.isMaster()) {
masterStub.executeByMaster(client, rcb, cr);
} else {
executeContractOnOtherNodes(cr, rcb);
}
break;
default:
break;
}
}
}
private void executeContractOnOtherNodes(ContractRequest cr, final ResultCallback rcb) {
ContractResult result;
if (null != nodeCenterConn && null != masterStub) {
String pubKey = nodeCenterConn.routeContract(cr.getContractID());
// TODO 如果此时master正在选举中先缓存请求有必要吗
// if(pubKey == null ||pubKey.equals("")){
// logger.info("Master正在崩溃选举中,先将请求缓存!");
// if(MasterClientRecoverMechAction.requestsToMaster == null){
// MasterClientRecoverMechAction.requestsToMaster = new
// ConcurrentHashMap<>();
// }
//
// if(!MasterClientRecoverMechAction.requestsToMaster.containsKey(c.getContractID())){
//
// MasterClientRecoverMechAction.requestsToMaster.put(c.getContractID(),new
// Queue<>());
// }
//
// MasterClientRecoverMechAction.requestsToMaster.get(c.getContractID()).add(new
// RequestToMaster(c));
// return;
// }
// LOGGER.info("查看合约 " + cr.getContractID() + " 的master为 " + pubKey);
if (!masterStub.hasConnection(pubKey)) {
pubKey = nodeCenterConn.reRouteContract(cr.getContractID());
LOGGER.info("查看合约 " + cr.getContractID() + " 的master为 " + pubKey);
}
if (null != pubKey) {
masterStub.executeByOtherNodeAsync(pubKey, cr, rcb);
return;
// result = masterStub.executeByOtherNode(pubKey, cr);
} else {
result =
new ContractResult(
Status.Error,
new JsonPrimitive(
"Contract "
+ cr.getContractID()
+ "can't be located in router"));
// 告知NC重选
/*
好像有点问题之前这么写是觉得找不到的话是因为master出问题了需要重选但是没考虑到这个合约确实不存在
但是可能也不影响如果这个合约确实不存在那么即使NC发起了选举也不会真的进行选举
*/
// JsonObject jo = new JsonObject();
// jo.addProperty("action", "NCStartElect");
// jo.addProperty("contractID", cr.getContractID());
// nodeCenterConn.sendMsg(JsonUtil.toJson(jo));
// LOGGER.info("发现合约 " + cr.getContractID() + "
// master为null发请求给master令其发启选举");
}
} else {
result =
new ContractResult(
Status.Error,
new JsonPrimitive(
"Contract " + cr.getContractID() + " doesn't exists!!"));
}
rcb.onResult(JsonUtil.toJson(result));
}
private ContractClient getByName(String contractName) {
return statusRecorder.getContractClient(contractName);
}
public String stopContract(String contractID) {
return statusRecorder.killContract(contractID);
}
//
public String stopContractWithOwner(final String owner, String contractID) {
LOGGER.info("[ContractManager] stopContractWithOwner : ");
boolean isNodeManager = checkNodeManager(owner);
ContractMeta meta = statusRecorder.getContractMeta(contractID);
if (meta != null) {
if (!meta.contract.getOwner().equals(owner) && !isNodeManager) {
return "Failed: Only the contract owner or node manager can stop a contract.";
}
return statusRecorder.killContract(meta);
} else {
return "contract:" + contractID + " not exists";
}
}
public String redirect(String contractID, PrintStream ps, String tag) {
ContractClient client = statusRecorder.getContractClient(contractID);
if (client.contractMeta.contract.isDebug()) {
client.outputTracer.redirect(ps, tag);
client.errorTracer.redirect(ps, tag);
return "success";
} else {
return "failed, not debug mode";
}
}
public int stopAllContracts() {
return statusRecorder.stopAllContracts();
}
public int stopAllContractsWithOwner(final String owner) {
return statusRecorder.stopAllContractsWithOwner(owner);
}
public String listTheContracts(String contractID) {
ContractMeta meta = statusRecorder.getContractMeta(contractID);
if (meta != null) {
ContractInfo info = fillContractInfo(meta);
return JsonUtil.toPrettyJson(info);
}
return "Contract Process not exist!";
}
private ContractInfo fillContractInfo(ContractMeta meta) {
ContractInfo info = new ContractInfo();
info.type = meta.contract.getType();
info.id = meta.contract.getID();
info.name = meta.name;
info.contractStatus = meta.status;
info.annotations = meta.getAnnotations();
info.exportedFunctions = meta.getExportedFunctions();
info.events = meta.getEvents();
info.yjsType = meta.getYjsType();
info.pubkey = meta.getPubkey();
info.contractPermission = meta.getThisPermission();
if (meta.status == ContractStatusEnum.RUNNING) {
ContractClient client = statusRecorder.getContractClient(meta.id);
info.port = String.valueOf(client.port);
client.memory = getMemoryByPID(client.getPID());
info.times = client.times;
info.traffic = convertToBytes(client.traffic);
info.storage = convertToBytes(client.memory);
}
return info;
}
private long getMemoryByPID(String pid) {
try {
long pidLong = Long.parseLong(pid);
if (sigar == null) {
sigar = new Sigar();
}
ProcMem procMem = sigar.getProcMem(pidLong);
return procMem.getResident();
} catch (Throwable e) {
return -1L;
}
}
public String listContracts(final String firstID) {
List<ContractInfo> ret = new ArrayList<>();
for (ContractMeta client : statusRecorder.getStatus().values()) {
if (client.status != ContractStatusEnum.KILLED) {
ContractInfo contractInfo = fillContractInfo(client);
ret.add(contractInfo);
}
}
sortContractInfoList(ret, firstID);
// System.out.println("[MsgHandler]" +
// JsonUtil.toPrettyJson(ret));
return JsonUtil.toPrettyJson(ret);
}
public String listContractsWithOwner(final String owner, final String firstID, int filters) {
boolean isNodeManager = checkNodeManager(owner);
List<ContractInfo> ret = new ArrayList<>();
for (ContractMeta client : statusRecorder.getStatus().values()) {
if (!client.contract.getOwner().equals(owner) && !isNodeManager) {
continue;
}
if (0 == filters || (filters & (1 << client.status.getCode())) > 0) {
ContractInfo contractInfo = fillContractInfo(client);
ret.add(contractInfo);
}
}
sortContractInfoList(ret, firstID);
// System.out.println("[MsgHandler]" +
// JsonUtil.toPrettyJson(ret));
return JsonUtil.toPrettyJson(ret);
}
void sortContractInfoList(List<ContractInfo> infoList, String firstID) {
infoList.sort(
(o1, o2) -> {
if (o1.id.equals(firstID)) {
return -1;
}
if (o2.id.equals(firstID)) {
return 1;
}
if (o1.name != null && o2.name != null) {
return o1.name.compareTo(o2.name);
} else {
return -1;
}
});
}
public String getContractResourceInfo() {
Map<String, Map<String, String>> cris = getContainerResourceInfoByTop();
List<ContractInfo> ret = new ArrayList<>();
for (ContractMeta client : statusRecorder.getStatus().values()) {
ContractInfo contractInfo = fillContractInfo(client);
ContractClient contractClient = statusRecorder.getContractClient(contractInfo.id);
if (contractClient != null) contractInfo.pid = contractClient.getPID();
else contractInfo.pid = "-1";
if (!contractInfo.pid.equals("-1") && !contractInfo.pid.equals("0")) {
try {
assert cris != null;
Map<String, String> cri = cris.get(contractInfo.pid);
contractInfo.cpu = cri.get("%CPU");
contractInfo.mem = cri.get("%MEM");
contractInfo.rss = cri.get("MEM");
} catch (Exception ex) {
ex.printStackTrace();
}
}
ret.add(contractInfo);
}
// System.out.println("[MsgHandler]" +
// JsonUtil.toPrettyJson(ret));
return JsonUtil.toJson(ret);
}
public String getFreeResourceInfo() {
try {
Map<String, String> freeResourceInfo = new HashMap<>();
String freeCPU = null;
String freeMEM = null;
float totalMEM = 0;
Process process = Runtime.getRuntime().exec("top -b -n 1");
InputStreamReader ir = new InputStreamReader(process.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
String line;
while ((line = input.readLine()) != null) {
// System.out.println(line);
if (line.contains("%Cpu(s):")) {
Scanner sc2 = new Scanner(new ByteArrayInputStream(line.getBytes()));
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNextFloat()) freeCPU = sc2.nextFloat() + "%";
sc2.close();
} else if (line.contains("MiB Mem :")) {
Scanner sc2 = new Scanner(new ByteArrayInputStream(line.getBytes()));
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNextFloat()) totalMEM = sc2.nextFloat();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNext()) sc2.next();
if (sc2.hasNextFloat())
freeMEM = String.format("%.1f", totalMEM - sc2.nextFloat()) + " MiB";
sc2.close();
}
}
freeResourceInfo.put("freeCPU", freeCPU);
freeResourceInfo.put("totalMEM", String.format("%.1f", totalMEM) + " MiB");
freeResourceInfo.put("freeMEM", freeMEM);
return JsonUtil.toJson(freeResourceInfo);
} catch (IOException e) {
e.printStackTrace();
return "getFreeResourceInfo failed.";
}
}
private long safeParseLong(String result) {
try {
return Long.parseLong(result);
} catch (Exception e) {
return 0L;
}
}
public String getGasEvaluates(String contractName, String functionName, String args) {
ContractClient client = getByName(contractName);
return client.get.syncGet("", "functionEvaluates", functionName);
}
public String resetPermission(String contractName, String permission, String isOpen) {
ContractClient client = getByName(contractName);
String change = permission + "," + isOpen;
String setDesktopPermission = client.get.syncGet("", "setDesktopPermission", change);
client.contractMeta.thisPermission = client.get.syncGet("", "showPermission", "");
return setDesktopPermission;
}
public String resetDebugFlag(String contractName, boolean isDebug) {
ContractClient client = getByName(contractName);
String result = client.get.syncGet("", "changeDebugFlag", String.valueOf(isDebug));
client.contractMeta.isDebug = isDebug;
return result;
}
/*
{
"name": "dx_substr",
"parameter":
{
"columnIndex":5,
"paras":["1","3"]
}
},
*/
/*public String resetMask(String contractName, JsonObject MaskObject) {
ContractClient client = getByName(contractName);
System.out.println("contractName"+client.getContractName());
//String result = client.get.syncGet("", "changeDebugFlag", String.valueOf(isDebug));
//設置clinet當中的mask client.contractMeta.isDebug = isDebug;
return "resetMask";
}*/
public String dumpContract(String contractID, String path) {
// LOGGER.info(contractID);
// LOGGER.info(contracts.keySet().toString());
ContractClient client = getClient(contractID);
addLocalContractLog("dumpContract", client.contractMeta);
// LOGGER.info(client.port);
// LOGGER.info(tmp);
return client.get.syncGet("", "getMemoryDump", path);
}
public String redo(String contractID, String path) {
ContractClient client = getClient(contractID);
if (null == client) {
return "contractID " + contractID + " not exists";
}
addLocalContractLog("redo", client.contractMeta);
return client.get.syncGet("", "redo", path);
}
public String getCachedTransRecords(String contractID, String startSeq) {
ContractClient client = getClient(contractID);
if (null == client) {
// return "contractID " + contractID + " not exists";
return "";
}
addLocalContractLog("getCachedTransRecords", client.contractMeta);
return client.get.syncGet("", "getCachedTransRecords", startSeq);
}
void addLocalContractLog(String content, ContractMeta meta) {
addLocalContractLog(content, meta.contract.getID(), meta.name, meta.contract.getOwner());
}
public String loadMemory(ContractClient client, String path) {
if (client == null) return "no such contract client";
addLocalContractLog("loadMemory", client.contractMeta);
return client.get.syncGet("", "loadMemory", path);
}
public List<ContractDesp> getContractDespList() {
List<ContractDesp> ret = new ArrayList<>();
for (ContractMeta meta : statusRecorder.getStatus().values()) {
if (meta.status == ContractStatusEnum.RUNNING
|| meta.status == ContractStatusEnum.HANGED) {
ContractDesp desc = new ContractDesp();
desc.contractID = meta.id;
desc.contractName = meta.name;
desc.events = meta.declaredEvents;
desc.exportedFunctions = meta.exportedFunctions;
desc.type = meta.contract.getType();
desc.annotations = meta.annotations;
desc.yjsType = meta.getYjsType();
desc.dependentContracts = meta.getDependentContracts();
MultiContractMeta multiContractMeta =
multiContractRecorder.getMultiContractMeta(meta.getID());
desc.setIsMaster(multiContractMeta != null && multiContractMeta.isMaster());
ret.add(desc);
}
}
return ret;
}
public String deliverEMessage(REvent msg) {
eventBroker.handle(msg);
return "success";
}
// ======log api
public ContractResult getLogSize(String contractID) {
try {
ContractClient client = getClient(contractID);
if (client != null) {
return new ContractResult(
Status.Success,
new JsonPrimitive(client.get.syncGet("", "getLogSize", "")));
}
// return new ContractResult(Status.Error, "cannot find contractID: " + contractID);
return new ContractResult(
Status.Error, new JsonPrimitive("cannot find contractID: " + contractID));
} catch (Exception e) {
e.printStackTrace();
return new ContractResult(Status.Exception, new JsonPrimitive(e.getMessage()));
}
}
public ContractResult requestLog(String contractID, long offset, int count) {
try {
ContractClient client = getClient(contractID);
if (client != null) {
return new ContractResult(
Status.Success,
new JsonPrimitive(
client.get.syncGet("", "requestLog", offset + "," + count)));
}
return new ContractResult(
Status.Error, new JsonPrimitive("cannot find contractID: " + contractID));
} catch (Exception e) {
e.printStackTrace();
return new ContractResult(Status.Exception, new JsonPrimitive(e.getMessage()));
}
}
public ContractResult requestLastLog(String contractID, int count) {
try {
ContractClient client = getClient(contractID);
if (client != null) {
return new ContractResult(
Status.Success,
new JsonPrimitive(
client.get.syncGet("", "requestLastLog", String.valueOf(count))));
}
return new ContractResult(
Status.Error, new JsonPrimitive("cannot find contractID: " + contractID));
} catch (Exception e) {
e.printStackTrace();
return new ContractResult(Status.Exception, new JsonPrimitive(e.getMessage()));
}
}
/*
public void addContractInfo(String name, String owner, String traffic, String times) {
KeyValueDBUtil.instance.setValue(
CMTables.ContractInfo.toString(),
name,
"{\"owner\":\""
+ owner
+ "\",\"traffic\":\""
+ traffic
+ "\",\"times\":\""
+ times
+ "\"}");
}
*/
public void addLocalContractLog(
String action, String contractId, String contractName, String pubKey) {
String sb =
"{\"action\":\""
+ action
+ "\",\"pubKey\":\""
+ pubKey
+ "\",\"contractID\":\""
+ contractId
+ "\",\"contractName\":\""
+ contractName
+ "\",\"date\":"
+ System.currentTimeMillis()
+ "}";
logsDB.put(contractName, sb);
}
public void changePermission(String contractFileName, String pmList) {
}
// public String getSyncType(String contractName) {
// ContractClient client = getByName(contractName);
// if (client == null) {
// return "No this contract process,failed";
// }
//
// String result = client.get.syncGet("", "getSyncType", "");
//
// addLocalContractLog(
// "getSyncType",
// client.contract.getID(),
// client.contractName,
// client.contract.getOwner());
// return result;
// }
// public String changeSyncType(String contractName, String type) {
// ContractClient client = getByName(contractName);
// if (client == null) {
// return "No this contract process,failed";
// }
//
// String result = client.get.syncGet("", "changeSyncType", type);
//
// addLocalContractLog(
// "changeSyncType",
// client.contract.getID(),
// client.contractName,
// client.contract.getOwner());
// return result;
// }
// public String recoverBySync(String contractName) {
// ContractClient client = getByName(contractName);
// if (client == null) {
// return "No this contract process,failed";
// }
//
// String result = client.get.syncGet("", "recoverBySync", "");
//
// addLocalContractLog(
// "recoverBySync",
// client.contract.getID(),
// client.contractName,
// client.contract.getOwner());
// return result;
// }
public void addLocalContractLog(
String action,
String contractId,
String contractName,
String pubKey,
String function,
String costTime,
long totalGas,
long executionGas,
long extraGas,
Map<String, String> logType) {
contractCounter.inc();
if (logType == null || logType.isEmpty()) {
logsDB.put(
contractName,
String.format(
"{\"action\":\"%s\",\"pubKey\":\"%s\","
+ "\"contractID\":\"%s\",\"contractName\":\"%s\","
+ "\"function\":\"%s\",\"costTime\":\"%s\","
+ "\"totalGas\":\"%d\",\"executionGas\":\"%d\","
+ "\"extraGas\":\"%d\",\"date\":\"%d\"}",
action,
pubKey,
contractId,
contractName,
function,
costTime,
totalGas,
executionGas,
extraGas,
System.currentTimeMillis()));
} else {
StringBuilder str =
new StringBuilder()
.append("{\"action\":\"")
.append(action)
.append("\",\"pubKey\":\"")
.append(pubKey)
.append("\",\"contractID\":\"")
.append(contractId)
.append("\",\"contractName\":\"")
.append(contractName)
.append("\",\"function\":\"")
.append(function)
.append("\",\"costTime\":\"")
.append(costTime)
.append("\",\"totalGas\":\"")
.append(totalGas)
.append("\",\"executionGas\":\"")
.append(executionGas)
.append("\",\"extraGas\":\"")
.append(extraGas);
for (String key : logType.keySet()) {
str.append("\",\"").append(key).append("\":\"").append(logType.get(key));
}
str.append("\",\"date\":").append(System.currentTimeMillis()).append("}");
logsDB.put(contractName, str.toString());
}
}
public String getTimesOfExecution(String contractName) {
return KeyValueDBUtil.instance.getValue(
CMTables.ContractInfo.toString(), contractName + "-Times");
}
public String getControlFlow(Contract c) {
if (null == analysisClient
|| null == analysisClient.process
|| !analysisClient.process.isAlive()) {
initAnalysisClient();
}
return analysisClient.get.syncGet("", "getControlFlow", JsonUtil.toJson(c));
}
// 解析本地合约日志
public boolean findConflictOfName(String contractName) {
ContractMeta meta = statusRecorder.getContractMeta(contractName);
return meta != null && meta.status == ContractStatusEnum.RUNNING;
}
public boolean findConflictOfDOI(String contractDOI) {
return null != statusRecorder.getContractMeta(contractDOI);
}
public void clearSyncFiles(String contractID) {
ContractClient client = getClient(contractID);
if (client == null) {
return;
}
addLocalContractLog("clearSyncFiles", client.contractMeta);
client.get.syncGet("", "clearSyncFiles", contractID);
}
public String setContractIsMaster(String contractID, String target) {
MultiContractMeta meta = multiContractRecorder.getMultiContractMeta(contractID);
if (null == meta) {
return null;
}
synchronized (meta) {
meta.setIsMaster(Boolean.parseBoolean(target));
multiContractRecorder.updateValue(meta);
addLocalContractLog("setContractIsMaster", statusRecorder.getContractMeta(contractID));
return "true";
}
}
public boolean getContractIsMaster(String contractID) {
MultiContractMeta meta = multiContractRecorder.getMultiContractMeta(contractID);
if (null == meta) {
return false;
}
return meta.isMaster();
}
public void startSync(String contractName) {
ContractClient client = getByName(contractName);
if (client == null) {
return;
}
client.get.syncGet("", "startSync", "");
addLocalContractLog("startSync", client.contractMeta);
}
public void stopSync(String contractName) {
ContractClient client = getByName(contractName);
if (client == null) {
return;
}
client.get.syncGet("", "stopSync", "");
addLocalContractLog("stopSync", client.contractMeta);
}
public void setCRFile(String contractName, String syncFileName) {
ContractClient client = getByName(contractName);
if (null == client) {
return;
}
client.get.syncGet("", "setCRFile", syncFileName);
addLocalContractLog("setCRFile", client.contractMeta);
}
public void invokeContractSuicide(ContractClient client) {
if (null != client) {
try {
String ret = client.get.syncGet("", "suicide", "");
JsonObject jo = JsonUtil.parseString(ret);
if (jo.has("cleanSub")) {
REvent msg =
new REvent(
null,
REvent.REventType.UNSUBSCRIBE,
"{\"subscriber\":\"" + client.getContractName() + "\"}",
"");
msg.doSignature(client.getPubkey(), client.getContractKey());
eventBroker.handle(msg);
}
} catch (Exception ignored) {
}
}
}
public String parseYpkPermissions(String ypkPath) {
if (null == analysisClient
|| null == analysisClient.process
|| !analysisClient.process.isAlive()) {
initAnalysisClient();
}
return analysisClient.get.syncGet("", "parseYpkPermissions", ypkPath);
}
public String staticVerify(Contract c) {
if (null == analysisClient
|| null == analysisClient.process
|| !analysisClient.process.isAlive()) {
initAnalysisClient();
}
return analysisClient.get.syncGet("", "staticVerify", JsonUtil.toJson(c));
}
// 合约状态
static class StrCollector extends ResultCallback {
String strRet = "{\"data\":\"Timeout\"}";
boolean hasResult = false;
long start = System.currentTimeMillis();
@Override
public void onResult(String str) {
synchronized (this) {
strRet = str;
hasResult = true;
this.notifyAll();
}
}
public void waitForResult() {
synchronized (this) {
try {
if (!hasResult) {
this.wait(5000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void waitForResultCounter(int count) {
synchronized (this) {
try {
if (!hasResult) {
this.wait(20000L * count);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Printer extends Thread {
Process p;
Scanner sc;
String TAG;
List<PrintStream> psList;
Set<PrintStream> toRemove;
public void track(Process process, Scanner sc, String tag, PrintStream printStream) {
p = process;
this.sc = sc;
this.TAG = tag;
psList = new ArrayList<>();
if (printStream != null) psList.add(printStream);
toRemove = new HashSet<>();
start();
}
public synchronized void redirect(PrintStream ps) {
psList.add(ps);
}
public void run() {
try {
while (sc.hasNextLine()) {
String content = sc.nextLine();
if (psList.size() == 0) {
LOGGER.info(content);
} else {
printInList(content);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
private synchronized void printInList(String content) {
for (PrintStream ps : psList) {
try {
ps.println(TAG + content);
} catch (Exception e) {
e.printStackTrace();
toRemove.add(ps);
}
}
psList.removeAll(toRemove);
toRemove.clear();
}
} // Printer
static class ContractInfo {
public String pubkey;
String id, name, port;
ContractExecType type;
// 合约状态,调用次数,流量统计,内存占用
String traffic, storage;
long times;
List<FunctionDesp> exportedFunctions;
Map<String, REventSemantics> events;
ContractStatusEnum contractStatus;
String contractPermission;
List<AnnotationNode> annotations;
// 进程ID占用CPU百分比占用MEM百分比占用物理内存byte数
String pid;
String cpu;
String mem;
String rss;
YjsType yjsType;
}
// public static void encryptContract(Contract c, String privKey) {
// String aes = AES2.generateAES();
// RSA rsa = RSA.generateFromBase64(privKey);
// String scriptStr = new
// BASE64Encoder().encode(rsa.decode(aes.getBytes()));
// String scriptStr = new BASE64Encoder().encode(rsa.decode(aes.getBytes()));
// scriptStr += ",";
// scriptStr += AES2.encrypt(aes, c.getScriptStr());
// c.setOwner(rsa.toBase64Pubkey());
// c.setScript(scriptStr);
// }
// Used for ContractManager restart.
}