diff --git a/.gitignore b/.gitignore
index 6fbce99db3..3a981cfc81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
/log/
/rt/
/web3/
+/zmq_keystore/
/jars/
# ide
diff --git a/aion_api b/aion_api
index e21f8e878d..6adb12f81c 160000
--- a/aion_api
+++ b/aion_api
@@ -1 +1 @@
-Subproject commit e21f8e878d598724176a6d0c51fceafc85239020
+Subproject commit 6adb12f81ce775989da3acb134d4b1c3a9e146eb
diff --git a/modAionBase/src/module-info.java b/modAionBase/src/module-info.java
index db43d3f590..20bbee63bf 100644
--- a/modAionBase/src/module-info.java
+++ b/modAionBase/src/module-info.java
@@ -4,5 +4,6 @@
exports org.aion.base.util;
exports org.aion.base.vm;
exports org.aion.base.db;
+ exports org.aion.base.io;
exports org.aion.base;
}
diff --git a/modAionBase/src/org/aion/base/io/File.java b/modAionBase/src/org/aion/base/io/File.java
new file mode 100644
index 0000000000..fabfeaf005
--- /dev/null
+++ b/modAionBase/src/org/aion/base/io/File.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017-2018 Aion foundation.
+ *
+ * This file is part of the aion network project.
+ *
+ * The aion network project is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or any later version.
+ *
+ * The aion network project is distributed in the hope that it will
+ * be useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with the aion network project source files.
+ * If not, see .
+ *
+ * Contributors:
+ * Aion foundation.
+ */
+
+package org.aion.base.io;
+
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class File {
+ public static List getFiles(final Path path) {
+ if (path == null) {
+ System.out.println("getFiles null path input!");
+ return Collections.emptyList();
+ }
+
+ try {
+ java.io.File[] files = path.toFile().listFiles();
+ return files != null ? Arrays.asList(files) : Collections.emptyList();
+ } catch (UnsupportedOperationException | NullPointerException e) {
+ System.out.println("getFiles exception: " + e.toString());
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/modAionImpl/build.xml b/modAionImpl/build.xml
index 1867a6d295..ad3ff92512 100644
--- a/modAionImpl/build.xml
+++ b/modAionImpl/build.xml
@@ -172,6 +172,8 @@
+
+
diff --git a/modAionImpl/src/module-info.java b/modAionImpl/src/module-info.java
index d59cc69e97..0fa7b4df30 100644
--- a/modAionImpl/src/module-info.java
+++ b/modAionImpl/src/module-info.java
@@ -1,4 +1,6 @@
module aion.zero.impl {
+ uses org.aion.evtmgr.EventMgrModule;
+ uses org.aion.txpool.TxPoolModule;
requires aion.base;
requires aion.mcf;
requires aion.log;
@@ -17,6 +19,9 @@
requires jdk.management;
requires java.xml;
requires slf4j.api;
+ requires com.google.common;
+ requires info.picocli;
+ requires commons.lang3;
exports org.aion.equihash;
exports org.aion.zero.impl.blockchain;
@@ -25,6 +30,7 @@
exports org.aion.zero.impl.types;
exports org.aion.zero.impl.config;
exports org.aion.zero.impl.cli;
+ opens org.aion.zero.impl.cli;
exports org.aion.zero.impl.db;
exports org.aion.zero.impl.sync;
exports org.aion.zero.impl.config.dynamic;
diff --git a/modApiServer/src/org/aion/api/server/ApiAion.java b/modApiServer/src/org/aion/api/server/ApiAion.java
index bcbece4e8b..d413feaefc 100644
--- a/modApiServer/src/org/aion/api/server/ApiAion.java
+++ b/modApiServer/src/org/aion/api/server/ApiAion.java
@@ -80,7 +80,7 @@ public abstract class ApiAion extends Api {
// 2. underlying datastructure provides concurrency guarntees
// delegate concurrency to underlying object
- protected static NrgOracle NRG_ORACLE;
+ private static NrgOracle NRG_ORACLE;
protected IAionChain ac; // assumption: blockchainImpl et al. provide concurrency guarantee
// using java.util.concurrent library objects
@@ -224,7 +224,7 @@ public AionBlock getBlock(long blkNr) {
}
}
- public Map.Entry getBlockWithTotalDifficulty(long blkNr) {
+ protected Map.Entry getBlockWithTotalDifficulty(long blkNr) {
if (blkNr > 0) {
return ((AionBlockStore) this.ac.getBlockchain().getBlockStore())
.getChainBlockByNumberWithTotalDifficulty(blkNr);
diff --git a/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java b/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java
index 5a7de9acdf..7e5da4b64c 100644
--- a/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java
+++ b/modApiServer/src/org/aion/api/server/zmq/HdlrZmq.java
@@ -1,4 +1,4 @@
-/*******************************************************************************
+/*
* Copyright (c) 2017-2018 Aion foundation.
*
* This file is part of the aion network project.
@@ -19,8 +19,7 @@
*
* Contributors:
* Aion foundation.
- *
- ******************************************************************************/
+ */
package org.aion.api.server.zmq;
@@ -70,7 +69,7 @@ public byte[] process(byte[] request, byte[] socketId) {
}
}
- public void getTxWait() {
+ void getTxWait() {
TxWaitingMappingUpdate txWait = null;
try {
txWait = this.api.takeTxWait();
@@ -107,15 +106,15 @@ public Map getFilter() {
return this.api.getFilter();
}
- public BlockingQueue getTxStatusQueue() {
+ BlockingQueue getTxStatusQueue() {
return this.api.getPendingStatus();
}
- public byte[] toRspMsg(byte[] msgHash, int txCode, String error) {
+ byte[] toRspMsg(byte[] msgHash, int txCode, String error) {
return ApiUtil.toReturnHeader(this.api.getApiVersion(), txCode, msgHash, error.getBytes());
}
- public byte[] toRspMsg(byte[] msgHash, int txCode, String error, byte[] result) {
+ byte[] toRspMsg(byte[] msgHash, int txCode, String error, byte[] result) {
return ApiUtil.toReturnHeader(this.api.getApiVersion(), txCode, msgHash, error.getBytes(), result);
}
@@ -124,7 +123,7 @@ public byte[] process(byte[] request) {
return null;
}
- public byte[] toRspEvtMsg(byte[] ecb) {
+ byte[] toRspEvtMsg(byte[] ecb) {
return ApiUtil.toReturnEvtHeader(this.api.getApiVersion(), ecb);
}
diff --git a/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java b/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java
index ff0338b7bf..50def756a7 100644
--- a/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java
+++ b/modApiServer/src/org/aion/api/server/zmq/ProtocolProcessor.java
@@ -27,7 +27,12 @@
import static org.zeromq.ZMQ.DEALER;
import static org.zeromq.ZMQ.ROUTER;
+import java.io.File;
+import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -53,22 +58,32 @@
public class ProtocolProcessor implements Runnable {
protected static final Logger LOG = AionLoggerFactory.getLogger(LogEnum.API.name());
- private final IHdlr handler;
private static final String AION_ZMQ_WK_TH = "inproc://aionZmqWkTh";
private static final String AION_ZMQ_CB_TH = "inproc://aionZmqCbTh";
private static final String AION_ZMQ_EV_TH = "inproc://aionZmqEvTh";
private static final String AION_ZMQ_HB_TH = "inproc://aionZmqHbTh";
-
- private CfgApiZmq cfgApi;
- private AtomicBoolean shutDown = new AtomicBoolean();
-
+ private final Path PATH;
private static final long zmqHWM = 100_000;
private static final int SOCKETID_LEN = 5;
private static final int SOCKET_RECV_TIMEOUT = 3000;
+ private final IHdlr handler;
+ private CfgApiZmq cfgApi;
+ private AtomicBoolean shutDown = new AtomicBoolean();
+ private byte[] curvePubKey;
+ private byte[] curveSecKey;
+
public ProtocolProcessor(IHdlr _handler, final CfgApiZmq cfg) {
this.handler = _handler;
this.cfgApi = cfg;
+
+ String storageDir = System.getProperty("local.storage.dir");
+ if (storageDir == null || storageDir.equalsIgnoreCase("")) {
+ storageDir = System.getProperty("user.dir");
+ }
+
+ String curveKeyPath = storageDir + "/" + CfgApiZmq.ZMQ_KEY_DIR;
+ PATH = Paths.get(curveKeyPath);
}
public void shutdown() throws InterruptedException {
@@ -90,6 +105,23 @@ public void run() {
// create router sock.
Socket feSock = ctx.socket(ROUTER);
+ if (cfgApi.isSecureConnectEnabledEnabled()) {
+ // Currently the system will only load the first pair of the key files.
+ loadCurveKeyPair();
+
+ if (curveSecKey != null && curvePubKey != null) {
+ feSock.setZAPDomain("global".getBytes());
+ feSock.setCurveServer(true);
+ feSock.setCurvePublicKey(curvePubKey);
+ feSock.setCurveSecretKey(curveSecKey);
+ LOG.info("Secure connection enabled!");
+ } else {
+ LOG.info("Can't find the keyfile for setup the connection. Secure connection disabled!");
+ }
+ } else {
+ LOG.info("Secure connection disabled!");
+ }
+
feSock.setSndHWM(zmqHWM);
feSock.bind(bindAddr);
@@ -144,6 +176,39 @@ public void run() {
}
}
+ private void loadCurveKeyPair() {
+ List files = org.aion.base.io.File.getFiles(PATH);
+ String nextLoad = "";
+ for (File f : files) {
+ if (f.getName().contains("zmqCurvePubkey")) {
+ try {
+ curvePubKey = Files.readAllBytes(f.toPath());
+ nextLoad = f.getName().replace("zmqCurvePubkey", "zmqCurveSeckey");
+ } catch (IOException e) {
+ LOG.error("Get zmqCurvePubkey exception! {}", e.toString());
+ }
+ } else if (f.getName().contains("zmqCurveSeckey")) {
+ try {
+ curveSecKey = Files.readAllBytes(f.toPath());
+ nextLoad = f.getName().replace("zmqCurveSeckey", "zmqCurvePubkey");
+ } catch (IOException e) {
+ LOG.error("Get zmqCurveSeckey exception! {}", e.toString());
+ }
+ } else if (nextLoad.contentEquals(f.getName())){
+ try {
+ if (nextLoad.contains("zmqCurveSeckey")) {
+ curveSecKey = Files.readAllBytes(f.toPath());
+ } else {
+ curvePubKey = Files.readAllBytes(f.toPath());
+ }
+ } catch (IOException e) {
+ LOG.error("Get zmqCurveSeckey exception! {}", e.toString());
+ }
+ break;
+ }
+ }
+ }
+
private void eventRun(Context ctx) {
Socket sock = ctx.socket(ZMQ.DEALER);
sock.connect(AION_ZMQ_EV_TH);
@@ -168,15 +233,18 @@ private void eventRun(Context ctx) {
}
if (!al.isEmpty()) {
- Message.rsp_EventCtCallback ecb = Message.rsp_EventCtCallback.newBuilder().addAllEc(al).build();
+ Message.rsp_EventCtCallback ecb = Message.rsp_EventCtCallback.newBuilder()
+ .addAllEc(al).build();
byte[] rsp = ((HdlrZmq) this.handler).toRspEvtMsg(ecb.toByteArray());
try {
- byte[] socketId = ByteBuffer.allocate(5).put(ByteUtil.longToBytes(i), 3, 5).array();
+ byte[] socketId = ByteBuffer.allocate(5)
+ .put(ByteUtil.longToBytes(i), 3, 5).array();
sock.send(socketId, ZMQ.SNDMORE);
sock.send(rsp, ZMQ.DONTWAIT);
} catch (Exception e) {
- LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage());
+ LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e
+ .getMessage());
}
}
}
@@ -220,19 +288,25 @@ private void callbackRun(Context ctx) {
}
byte[] rsp = tps.toTxReturnCode() != 105
- ? ((HdlrZmq) this.handler).toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError())
- : ((HdlrZmq) this.handler).toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError(), tps.getTxResult());
+ ? ((HdlrZmq) this.handler)
+ .toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError())
+ : ((HdlrZmq) this.handler)
+ .toRspMsg(tps.getMsgHash(), tps.toTxReturnCode(), tps.getError(),
+ tps.getTxResult());
if (LOG.isTraceEnabled()) {
- LOG.trace("callbackRun send. socketID: [{}], msgHash: [{}], txReturnCode: [{}]/n rspMsg: [{}]",
- Hex.toHexString(tps.getSocketId()), Hex.toHexString(tps.getMsgHash()), tps.toTxReturnCode(),
- Hex.toHexString(rsp));
+ LOG.trace(
+ "callbackRun send. socketID: [{}], msgHash: [{}], txReturnCode: [{}]/n rspMsg: [{}]",
+ Hex.toHexString(tps.getSocketId()), Hex.toHexString(tps.getMsgHash()),
+ tps.toTxReturnCode(),
+ Hex.toHexString(rsp));
}
try {
sock.send(tps.getSocketId(), ZMQ.SNDMORE);
sock.send(rsp, ZMQ.DONTWAIT);
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
- LOG.error("ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage());
+ LOG.error(
+ "ProtocolProcessor.callbackRun sock.send exception: " + e.getMessage());
}
}
}
@@ -251,7 +325,8 @@ private void workerRun(ZMQ.Context ctx) {
try {
byte[] socketId = sock.recv(0);
if (LOG.isTraceEnabled()) {
- LOG.trace("ProtocolProcessor.workerRun socketID: [{}]", Hex.toHexString(socketId));
+ LOG.trace("ProtocolProcessor.workerRun socketID: [{}]",
+ Hex.toHexString(socketId));
}
if (socketId != null && socketId.length == SOCKETID_LEN) {
byte[] req = sock.recv(0);
diff --git a/modBoot/resource/custom/config.xml b/modBoot/resource/custom/config.xml
index 645f43f1ec..46885fbb6d 100644
--- a/modBoot/resource/custom/config.xml
+++ b/modBoot/resource/custom/config.xml
@@ -11,7 +11,9 @@
1
-
+
+ true
+
10E9
diff --git a/modBoot/resource/mainnet/config.xml b/modBoot/resource/mainnet/config.xml
index bedb9e6e89..60d31003eb 100644
--- a/modBoot/resource/mainnet/config.xml
+++ b/modBoot/resource/mainnet/config.xml
@@ -4,12 +4,15 @@
[NODE-ID-PLACEHOLDER]
-
+
false
web3,eth,personal,stratum,ops
-
+
+ true
+
+
10E9
diff --git a/modBoot/resource/mastery/config.xml b/modBoot/resource/mastery/config.xml
index 1f1ec44ce6..20e59bc45e 100755
--- a/modBoot/resource/mastery/config.xml
+++ b/modBoot/resource/mastery/config.xml
@@ -9,7 +9,9 @@
web3,eth,personal,stratum,ops
-
+
+ true
+
10E9
diff --git a/modBoot/src/module-info.java b/modBoot/src/module-info.java
index fb01f68383..d0fd73da79 100644
--- a/modBoot/src/module-info.java
+++ b/modBoot/src/module-info.java
@@ -1,4 +1,6 @@
module aion.boot {
+ uses org.aion.evtmgr.EventMgrModule;
+ uses org.aion.log.AionLoggerFactory;
requires aion.crypto;
requires aion.apiserver;
@@ -9,8 +11,8 @@
requires slf4j.api;
requires aion.p2p;
requires aion.fastvm;
-
-
+ requires aion.base;
+ requires libnzmq;
exports org.aion;
}
diff --git a/modBoot/src/org/aion/Aion.java b/modBoot/src/org/aion/Aion.java
index 7281620beb..5f6b2baa79 100644
--- a/modBoot/src/org/aion/Aion.java
+++ b/modBoot/src/org/aion/Aion.java
@@ -30,8 +30,17 @@
import static org.aion.zero.impl.cli.Cli.ReturnType;
import java.io.Console;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.ServiceLoader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
import java.util.function.Consumer;
import org.aion.api.server.http.RpcServer;
import org.aion.api.server.http.RpcServerBuilder;
@@ -49,6 +58,7 @@
import org.aion.log.LogEnum;
import org.aion.mcf.account.Keystore;
import org.aion.mcf.config.CfgApiRpc;
+import org.aion.mcf.config.CfgApiZmq;
import org.aion.mcf.config.CfgSsl;
import org.aion.mcf.mine.IMineRunner;
import org.aion.solidity.Compiler;
@@ -59,6 +69,7 @@
import org.aion.zero.impl.config.CfgAion;
import org.aion.zero.impl.config.Network;
import org.slf4j.Logger;
+import org.zeromq.ZMQ;
public class Aion {
@@ -88,11 +99,22 @@ public static void main(String args[]) {
exit(ret.getValue());
}
+ //Check ZMQ server secure connect settings, generate keypair when the settings enabled and can't find the keypair.
+ if (cfg.getApi().getZmq().getActive() && cfg.getApi().getZmq()
+ .isSecureConnectEnabledEnabled()) {
+ try {
+ checkZmqKeyPair();
+ } catch (Exception e) {
+ System.out.println("Check zmq keypair fail! " + e.toString());
+ exit(1);
+ }
+ }
+
// UUID check
String UUID = cfg.getId();
if (!UUID.matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) {
System.out.println("Invalid UUID; please check setting in config.xml");
- exit(-1);
+ exit(1);
}
ServiceLoader.load(EventMgrModule.class);
@@ -138,7 +160,7 @@ public static void main(String args[]) {
filePath[6] = cfg.getInitialGenesisFile().getAbsolutePath();
String path =
- "\n-------------------------------- USED PATHS --------------------------------" +
+ "\n-------------------------------- USED PATHS --------------------------------" +
"\n> Logger path: " + filePath[0] +
"\n> Database path: " + filePath[1] +
"\n> Keystore path: " + filePath[2] +
@@ -150,7 +172,7 @@ public static void main(String args[]) {
"\n----------------------------------------------------------------------------\n\n";
String logo =
- "\n _____ \n" +
+ "\n _____ \n" +
" .'. | .~ ~. |.. |\n" +
" .' `. | | | | ``.. |\n" +
" .''''''''`. | | | | ``.. |\n" +
@@ -163,6 +185,7 @@ public static void main(String args[]) {
if (networkStr == null && cfg.getNet().getId() >= 0) {
networkStr = Network.determineNetwork(cfg.getNet().getId()).toString();
}
+
logo = appendLogo(logo, versionStr);
if (networkStr != null) {
logo = appendLogo(logo, networkStr);
@@ -216,8 +239,8 @@ public static void main(String args[]) {
}
RpcServer rpcServer = null;
- if(cfg.getApi().getRpc().isActive()) {
- CfgApiRpc rpcCfg = cfg.getApi().getRpc();
+ if (cfg.getApi().getRpc().isActive()) {
+ CfgApiRpc rpcCfg = cfg.getApi().getRpc();
Consumer>> commonRpcConfig = (rpcBuilder) -> {
rpcBuilder.setUrl(rpcCfg.getIp(), rpcCfg.getPort());
@@ -230,14 +253,17 @@ public static void main(String args[]) {
rpcBuilder.setRequestQueueSize(rpcCfg.getRequestQueueSize());
rpcBuilder.setStuckThreadDetectorEnabled(rpcCfg.isStuckThreadDetectorEnabled());
- if (rpcCfg.isCorsEnabled())
+ if (rpcCfg.isCorsEnabled()) {
rpcBuilder.enableCorsWithOrigin(rpcCfg.getCorsOrigin());
+ }
CfgSsl cfgSsl = rpcCfg.getSsl();
- if (cfgSsl.getEnabled())
+ if (cfgSsl.getEnabled()) {
rpcBuilder.enableSsl(cfgSsl.getCert(), sslPass);
+ }
};
- RpcServerVendor rpcVendor = RpcServerVendor.fromString(rpcCfg.getVendor()).orElse(RpcServerVendor.UNDERTOW);
+ RpcServerVendor rpcVendor = RpcServerVendor.fromString(rpcCfg.getVendor())
+ .orElse(RpcServerVendor.UNDERTOW);
try {
switch (rpcVendor) {
case NANO: {
@@ -258,9 +284,11 @@ public static void main(String args[]) {
genLog.error("Failed to instantiate RPC server.", e);
}
- if (rpcServer == null)
- throw new IllegalStateException("Issue with RPC settings caused server instantiation to fail. " +
+ if (rpcServer == null) {
+ throw new IllegalStateException(
+ "Issue with RPC settings caused server instantiation to fail. " +
"Please check RPC settings in config file.");
+ }
rpcServer.start();
}
@@ -276,7 +304,8 @@ class ShutdownThreadHolder {
private final ProtocolProcessor pp;
private final RpcServer rpc;
- private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor pp, RpcServer rpc) {
+ private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor pp,
+ RpcServer rpc) {
this.zmqThread = zmqThread;
this.miner = nm;
this.pp = pp;
@@ -336,10 +365,78 @@ private ShutdownThreadHolder(Thread zmqThread, IMineRunner nm, ProtocolProcessor
}
- public static String appendLogo(String value, String input) {
+ private static void checkZmqKeyPair() throws IOException {
+ File zmqkeyDir = new File(
+ System.getProperty("user.dir") + File.separator + CfgApiZmq.ZMQ_KEY_DIR);
+
+ if (!zmqkeyDir.isDirectory()) {
+ if (!zmqkeyDir.mkdir()) {
+ System.out.println("zmq keystore directory could not be created. " +
+ "Please check user permissions or create directory manually.");
+ System.exit(1);
+ }
+ System.out.println();
+ }
+
+ if (!existZmqSecKeyFile(zmqkeyDir.toPath())) {
+ System.out.print("Can't find zmq key pair, generate new pair! \n");
+ ZMQ.Curve.KeyPair kp = ZMQ.Curve.generateKeyPair();
+ genKeyFile(zmqkeyDir.getPath(), kp.publicKey, kp.secretKey);
+ } else {
+ System.out.print("Find zmq key pair! \n");
+ }
+
+ }
+
+ private static boolean existZmqSecKeyFile(final Path path) {
+ List files = org.aion.base.io.File.getFiles(path);
+
+ for (File file : files) {
+ if (file.getName().contains("zmqCurveSeckey")) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static void genKeyFile(final String path, final String publicKey,
+ final String secretKey) throws IOException {
+ DateFormat df = new SimpleDateFormat("yy-MM-dd'T'HH-mm-ss'Z'");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ String iso_date = df.format(new Date(System.currentTimeMillis()));
+
+ String fileName = "UTC--" + iso_date + "--zmqCurvePubkey";
+ writeKeyToFile(path, fileName, publicKey);
+
+ fileName = "UTC--" + iso_date + "--zmqCurveSeckey";
+ writeKeyToFile(path, fileName, secretKey);
+ }
+
+ private static void writeKeyToFile(final String path, final String fileName, final String key)
+ throws IOException {
+ Set perms = PosixFilePermissions.fromString("rwxr-----");
+ FileAttribute> attr = PosixFilePermissions.asFileAttribute(perms);
+
+ Path p = Paths.get(path).resolve(fileName);
+ Path keyFile;
+ if (!java.nio.file.Files.exists(p)) {
+ keyFile = java.nio.file.Files.createFile(p, attr);
+ } else {
+ keyFile = p;
+ }
+
+ FileOutputStream fos = new FileOutputStream(keyFile.toString());
+ fos.write(key.getBytes());
+ fos.close();
+ }
+
+ private static String appendLogo(String value, String input) {
int leftPad = Math.round((44 - input.length()) / 2.0f) + 1;
StringBuilder padInput = new StringBuilder();
- for (int i = 0; i < leftPad; i++) padInput.append(" ");
+ for (int i = 0; i < leftPad; i++) {
+ padInput.append(" ");
+ }
padInput.append(input);
value += padInput.toString();
value += "\n\n";
@@ -358,7 +455,8 @@ private static char[] getSslPassword(CfgAion cfg) {
// 2) process started in non-interactive mode (background scheduler, redirected output, etc.)
// don't wan't to compromise security in these scenarios
if (console == null) {
- System.out.println("SSL-certificate-use requested with RPC server and no console found. " +
+ System.out.println(
+ "SSL-certificate-use requested with RPC server and no console found. " +
"Please set the ssl password in the config file (insecure) to run kernel non-interactively with this option.");
exit(1);
} else {
@@ -366,7 +464,7 @@ private static char[] getSslPassword(CfgAion cfg) {
console.printf("----------- INTERACTION REQUIRED ------------\n");
console.printf("---------------------------------------------\n");
sslPass = console.readPassword("Password for SSL keystore file ["
- +sslCfg.getCert()+"]\n");
+ + sslCfg.getCert() + "]\n");
}
}
diff --git a/modCrypto/src/module-info.java b/modCrypto/src/module-info.java
index 8d38edb738..1c8388def6 100644
--- a/modCrypto/src/module-info.java
+++ b/modCrypto/src/module-info.java
@@ -2,6 +2,7 @@
requires slf4j.api;
requires aion.base;
requires aion.rlp;
+ requires libnsc;
exports org.aion.crypto;
exports org.aion.crypto.hash;
exports org.aion.crypto.ed25519;
diff --git a/modMcf/src/module-info.java b/modMcf/src/module-info.java
index d902a5bd56..8c0589c0fe 100644
--- a/modMcf/src/module-info.java
+++ b/modMcf/src/module-info.java
@@ -7,6 +7,7 @@
requires aion.db.impl;
requires slf4j.api;
requires aion.p2p;
+ requires com.google.common;
exports org.aion.mcf.account;
exports org.aion.mcf.blockchain;
diff --git a/modMcf/src/org/aion/mcf/account/Keystore.java b/modMcf/src/org/aion/mcf/account/Keystore.java
index b2b572888f..7d1013db8d 100644
--- a/modMcf/src/org/aion/mcf/account/Keystore.java
+++ b/modMcf/src/org/aion/mcf/account/Keystore.java
@@ -1,5 +1,4 @@
/*
- ******************************************************************************
* Copyright (c) 2017-2018 Aion foundation.
*
* This file is part of the aion network project.
@@ -18,12 +17,6 @@
* along with the aion network project source files.
* If not, see .
*
- * The aion network project leverages useful source code from other
- * open source projects. We greatly appreciate the effort that was
- * invested in these projects and we thank the individual contributors
- * for their work. For provenance information and contributors
- * please see .
- *
* Contributors to the aion source files in decreasing order of code volume:
* Aion foundation.
* team through the ethereumJ library.
@@ -32,8 +25,9 @@
* Samuel Neves through the BLAKE2 implementation.
* Zcash project team.
* Bitcoinj team.
- *****************************************************************************
*/
+
+
package org.aion.mcf.account;
import java.io.File;
@@ -48,8 +42,6 @@
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -92,11 +84,6 @@ public class Keystore {
PATH = Paths.get(KEYSTORE_PATH);
}
- private static List getFiles() {
- File[] files = PATH.toFile().listFiles();
- return files != null ? Arrays.asList(files) : Collections.emptyList();
- }
-
public static String create(String password) {
return create(password, ECKeyFac.inst().create());
}
@@ -160,7 +147,7 @@ public static Map backupAccount(Map
throw new NullPointerException();
}
- List files = getFiles();
+ List files = org.aion.base.io.File.getFiles(PATH);
if (files == null) {
if (LOG.isWarnEnabled()) {
LOG.warn("No key file been stored in the kernel.");
@@ -213,7 +200,7 @@ public static Map backupAccount(Map
}
public static String[] list() {
- return addAddrs(getFiles()).toArray(new String[0]);
+ return addAddrs(org.aion.base.io.File.getFiles(PATH)).toArray(new String[0]);
}
private static List addAddrs(List files) {
@@ -240,7 +227,7 @@ private static List addAddrs(List files) {
* @return address represent by String as a List
*/
public static List accountsSorted() {
- List files = getFiles();
+ List files = org.aion.base.io.File.getFiles(PATH);
files.sort(COMPARE);
return addAddrs(files);
}
@@ -252,7 +239,7 @@ public static ECKey getKey(String _address, String _password) {
ECKey key = null;
if (_address.startsWith(AION_PREFIX)) {
- List files = getFiles();
+ List files = org.aion.base.io.File.getFiles(PATH);
for (File file : files) {
if (HEX_64.matcher(_address).find() && file.getName().contains(_address)) {
try {
@@ -282,7 +269,7 @@ public static boolean exist(String _address) {
boolean flag = false;
if (_address.startsWith(AION_PREFIX)) {
- List files = getFiles();
+ List files = org.aion.base.io.File.getFiles(PATH);
for (File file : files) {
if (HEX_64.matcher(_address).find() && file.getName().contains(_address)) {
flag = true;
@@ -338,7 +325,7 @@ public static Set importAccount(Map importKey) {
* Test method. Don't use it for the code dev.
*/
static File getAccountFile(String address, String password) {
- List files = getFiles();
+ List files = org.aion.base.io.File.getFiles(PATH);
if (files == null) {
if (LOG.isWarnEnabled()) {
LOG.warn("No key file been stored in the kernel.");
diff --git a/modMcf/src/org/aion/mcf/config/CfgApiZmq.java b/modMcf/src/org/aion/mcf/config/CfgApiZmq.java
index b86bdfe93c..74520ef5ca 100644
--- a/modMcf/src/org/aion/mcf/config/CfgApiZmq.java
+++ b/modMcf/src/org/aion/mcf/config/CfgApiZmq.java
@@ -1,11 +1,11 @@
-/*******************************************************************************
+/*
* Copyright (c) 2017-2018 Aion foundation.
*
* This file is part of the aion network project.
*
* The aion network project is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3 of
+ * as published by the Free Software Foundation, either versio 3 of
* the License, or any later version.
*
* The aion network project is distributed in the hope that it will
@@ -19,38 +19,41 @@
*
* Contributors:
* Aion foundation.
- *
- ******************************************************************************/
+ */
package org.aion.mcf.config;
import com.google.common.base.Objects;
-
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import org.aion.log.AionLoggerFactory;
+import org.slf4j.Logger;
public class CfgApiZmq {
+ public static final String ZMQ_KEY_DIR = "zmq_keystore";
+
CfgApiZmq() {
this.active = true;
this.ip = "127.0.0.1";
this.port = 8547;
this.filtersEnabled = true;
this.blockSummaryCacheEnabled = false;
+ this.secureConnectEnabled = false;
}
protected boolean active;
protected String ip;
protected int port;
- protected boolean filtersEnabled;
- protected boolean blockSummaryCacheEnabled;
+ private boolean filtersEnabled;
+ private boolean blockSummaryCacheEnabled;
+ private boolean secureConnectEnabled;
+
+ private static Logger LOG_GEN = AionLoggerFactory.getLogger("GEN");
public void fromXML(final XMLStreamReader sr) throws XMLStreamException {
this.active = Boolean.parseBoolean(sr.getAttributeValue(null, "active"));
@@ -69,16 +72,22 @@ public void fromXML(final XMLStreamReader sr) throws XMLStreamException {
try {
filtersEnabled = Boolean.parseBoolean(Cfg.readValue(sr));
} catch (Exception e) {
- //System.out.println("failed to read config node: aion.api.rpc.filters-enabled; using preset: " + this.filtersEnabled);
- //e.printStackTrace();
+ LOG_GEN.warn("failed to read config node: aion.api.zmq.filters-enabled; using preset: {}\n {}" + this.filtersEnabled, e);
+ e.printStackTrace();
}
break;
case "block-summary-cache":
try {
blockSummaryCacheEnabled = Boolean.parseBoolean(Cfg.readValue(sr));
} catch (Exception e) {
- //System.out.println("failed to read config node: aion.api.rpc.filters-enabled; using preset: " + this.filtersEnabled);
- //e.printStackTrace();
+ LOG_GEN.warn("failed to read config node: aion.api.zmq.block-summary-cache; using preset: {}\n {}", this.blockSummaryCacheEnabled, e);
+ }
+ break;
+ case "secure-connect":
+ try {
+ secureConnectEnabled = Boolean.parseBoolean(Cfg.readValue(sr));
+ } catch (Exception e) {
+ LOG_GEN.warn("failed to read config node: aion.api.zmq.secure-connect; using preset: {}\n {}" + this.secureConnectEnabled, e);
}
break;
default:
@@ -111,6 +120,12 @@ String toXML() {
xmlWriter.writeAttribute("ip", this.ip);
xmlWriter.writeAttribute("port", this.port + "");
+ xmlWriter.writeCharacters("\r\n\t\t\t");
+ xmlWriter.writeStartElement("secure-connect");
+ xmlWriter.writeCharacters(String.valueOf(this.secureConnectEnabled));
+ xmlWriter.writeEndElement();
+
+ xmlWriter.writeCharacters("\r\n\t\t");
xmlWriter.writeEndElement();
xml = strWriter.toString();
strWriter.flush();
@@ -135,6 +150,8 @@ public int getPort() {
}
public boolean isFiltersEnabled() { return this.filtersEnabled; }
public boolean isBlockSummaryCacheEnabled() { return this.blockSummaryCacheEnabled; }
+ public boolean isSecureConnectEnabledEnabled() { return this.secureConnectEnabled; }
+
@Override
public boolean equals(Object o) {
@@ -145,11 +162,12 @@ public boolean equals(Object o) {
port == cfgApiZmq.port &&
filtersEnabled == cfgApiZmq.filtersEnabled &&
blockSummaryCacheEnabled == cfgApiZmq.blockSummaryCacheEnabled &&
+ secureConnectEnabled == cfgApiZmq.secureConnectEnabled &&
Objects.equal(ip, cfgApiZmq.ip);
}
@Override
public int hashCode() {
- return Objects.hashCode(active, ip, port, filtersEnabled, blockSummaryCacheEnabled);
+ return Objects.hashCode(active, ip, port, filtersEnabled, blockSummaryCacheEnabled, secureConnectEnabled);
}
}