mirror of
https://gitee.com/BDWare/cm
synced 2025-04-27 06:22:17 +00:00
2329 lines
92 KiB
Java
2329 lines
92 KiB
Java
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需要检查A,B不能直接返回,需要"等待一半以上的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.
|
||
|
||
}
|