diff --git a/pom.xml b/pom.xml index 56d66af77..e1849b9b9 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,6 @@ 4.1.97.Final 2.3.1 - 1.0.0-RELEASE 2.14.2 5.4.0 1.18.26 @@ -88,18 +87,6 @@ always - - libp2p-jvm-libp2p - https://dl.cloudsmith.io/public/libp2p/jvm-libp2p/maven/ - - true - always - - - true - always - - hyperledger.jfrog.io https://hyperledger.jfrog.io/artifactory/besu-maven/ @@ -532,82 +519,6 @@ - - io.libp2p - jvm-libp2p - ${libp2p.version} - - - org.jetbrains - annotations - - - io.netty - netty-all - - - io.netty - netty-buffer - - - io.netty - netty-common - - - io.netty - netty-handler - - - io.netty - netty-transport - - - io.netty - netty-codec-http - - - org.bouncycastle - bcpkix-jdk15on - - - org.bouncycastle - bcprov-jdk15on - - - com.google.guava - guava - - - org.apache.logging.log4j - log4j-core - - - commons-codec - commons-codec - - - org.apache.logging.log4j - log4j-api - - - kotlin-stdlib - org.jetbrains.kotlin - - - kotlin-stdlib-common - org.jetbrains.kotlin - - - kotlin-stdlib-jdk8 - org.jetbrains.kotlin - - - slf4j-api - org.slf4j - - - - com.github.ben-manes.caffeine caffeine diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 30907102c..407d99eb4 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -24,9 +24,6 @@ package io.xdag; -import io.libp2p.core.crypto.KEY_TYPE; -import io.libp2p.core.crypto.KeyKt; -import io.libp2p.core.crypto.PrivKey; import io.xdag.cli.TelnetServer; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; @@ -40,21 +37,13 @@ import io.xdag.db.*; import io.xdag.db.mysql.TransactionHistoryStoreImpl; import io.xdag.db.rocksdb.*; -import io.xdag.mine.MinerServer; -import io.xdag.mine.manager.AwardManager; -import io.xdag.mine.manager.AwardManagerImpl; -import io.xdag.mine.manager.MinerManager; -import io.xdag.mine.manager.MinerManagerImpl; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerStates; -import io.xdag.mine.randomx.RandomX; -import io.xdag.net.XdagClient; -import io.xdag.net.XdagServer; -import io.xdag.net.libp2p.Libp2pNetwork; -import io.xdag.net.manager.NetDBManager; -import io.xdag.net.manager.XdagChannelManager; +import io.xdag.crypto.RandomX; +import io.xdag.net.PeerClient; +import io.xdag.net.PeerServer; +import io.xdag.net.NetDBManager; +import io.xdag.net.ChannelManager; import io.xdag.net.message.MessageQueue; -import io.xdag.net.message.NetDB; +import io.xdag.net.NetDB; import io.xdag.net.node.NodeManager; import io.xdag.rpc.Web3; import io.xdag.rpc.Web3Impl; @@ -63,12 +52,12 @@ import io.xdag.rpc.netty.*; import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; import io.xdag.rpc.serialize.JsonRpcSerializer; -import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.tuweni.bytes.Bytes; +import org.hyperledger.besu.crypto.KeyPair; import java.net.InetAddress; import java.net.UnknownHostException; @@ -81,48 +70,43 @@ @Setter public class Kernel { - private Status status = Status.STOPPED; - private Config config; - private Wallet wallet; - private DatabaseFactory dbFactory; - private AddressStore addressStore; - private BlockStore blockStore; - private OrphanBlockStore orphanBlockStore; - private TransactionHistoryStore txHistoryStore; - - private SnapshotStore SnapshotStore; - private Blockchain blockchain; - private NetDB netDB; - private XdagClient client; - private XdagChannelManager channelMgr; - private NodeManager nodeMgr; - private NetDBManager netDBMgr; - private XdagServer p2p; - private XdagSync sync; - private XdagPow pow; + protected Status status = Status.STOPPED; + protected Config config; + protected Wallet wallet; + protected KeyPair coinbase; + protected DatabaseFactory dbFactory; + protected AddressStore addressStore; + protected BlockStore blockStore; + protected OrphanBlockStore orphanBlockStore; + protected TransactionHistoryStore txHistoryStore; + + protected SnapshotStore SnapshotStore; + protected Blockchain blockchain; + protected NetDB netDB; + protected PeerClient client; + protected ChannelManager channelMgr; + protected NodeManager nodeMgr; + protected NetDBManager netDBMgr; + protected PeerServer p2p; + protected XdagSync sync; + protected XdagPow pow; private SyncManager syncMgr; - private byte[] firstAccount; - private Block firstBlock; - private Miner poolMiner; - private AwardManager awardManager; - private MinerManager minerManager; - private MinerServer minerServer; - private XdagState xdagState; - private Libp2pNetwork libp2pNetwork; - // protected DiscoveryController discoveryController; - private AtomicInteger channelsAccount = new AtomicInteger(0); - private PrivKey privKey = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).component1(); + protected byte[] firstAccount; + protected Block firstBlock; + protected XdagState xdagState; - private TelnetServer telnetServer; + protected AtomicInteger channelsAccount = new AtomicInteger(0); - private RandomX randomx; + protected TelnetServer telnetServer; + + protected RandomX randomx; // 记录运行状态 - private AtomicBoolean isRunning = new AtomicBoolean(false); + protected AtomicBoolean isRunning = new AtomicBoolean(false); // 记录启动时间片 @Getter - private long startEpoch; + protected long startEpoch; // rpc @@ -136,13 +120,15 @@ public class Kernel { public Kernel(Config config, Wallet wallet) { this.config = config; this.wallet = wallet; + this.coinbase = wallet.getDefKey(); this.xdagState = XdagState.INIT; this.telnetServer = new TelnetServer(config.getAdminSpec().getTelnetIp(), config.getAdminSpec().getTelnetPort(), this); } - public Kernel(Config config) { + public Kernel(Config config, KeyPair coinbase) { this.config = config; + this.coinbase = coinbase; } /** @@ -158,7 +144,7 @@ public synchronized void testStart() throws Exception { // ==================================== // start channel manager // ==================================== - channelMgr = new XdagChannelManager(this); + channelMgr = new ChannelManager(this); channelMgr.start(); log.info("Channel Manager start..."); netDBMgr = new NetDBManager(this.config); @@ -220,7 +206,6 @@ public synchronized void testStart() throws Exception { // 如果是第一次启动,则新建一个创世块 if (xdagStats.getOurLastBlockHash() == null) { firstAccount = Keys.toBytesAddress(wallet.getDefKey().getPublicKey()); - poolMiner = new Miner(BytesUtils.arrayToByte32(firstAccount)); firstBlock = new Block(config, XdagTime.getCurrentTimestamp(), null, null, false, null, null, -1); firstBlock.signOut(wallet.getDefKey()); xdagStats.setOurLastBlockHash(firstBlock.getHashLow().toArray()); @@ -230,7 +215,6 @@ public synchronized void testStart() throws Exception { blockchain.tryToConnect(firstBlock); } else { firstAccount = Keys.toBytesAddress(wallet.getDefKey().getPublicKey()); - poolMiner = new Miner(BytesUtils.arrayToByte32(firstAccount)); } log.info("Blockchain init"); @@ -263,11 +247,10 @@ public synchronized void testStart() throws Exception { // set up client // ==================================== - p2p = new XdagServer(this); + p2p = new PeerServer(this); p2p.start(); log.info("Node server start..."); - client = new XdagClient(this.config); - log.info("XdagClient nodeId {}", client.getNode().getHexId()); + client = new PeerClient(this.config, this.coinbase); // libp2pNetwork = new Libp2pNetwork(this); // libp2pNetwork.start(); @@ -296,29 +279,10 @@ public synchronized void testStart() throws Exception { syncMgr.start(); log.info("SyncManager start..."); - // ==================================== - // set up pool miner - // ==================================== - poolMiner.setMinerStates(MinerStates.MINER_SERVICE); - - // ==================================== - // set up minermanager awardmanager - // ==================================== - minerManager = new MinerManagerImpl(this); - awardManager = new AwardManagerImpl(this); - // ==================================== - // poolnode open - // ==================================== - minerServer = new MinerServer(this); - log.info("Pool Server init"); - // ==================================== // pow // ==================================== pow = new XdagPow(this); - minerManager.setPoW(pow); - minerManager.start(); - awardManager.start(); // register pow blockchain.registerListener(pow); @@ -461,8 +425,7 @@ public synchronized void testStop() { log.info("Node manager stop."); log.info("ChannelManager stop."); -// discoveryController.stop(); -// libp2pNetwork.stop(); + // close timer MessageQueue.timer.shutdown(); @@ -473,12 +436,6 @@ public synchronized void testStop() { client.close(); log.info("Node client stop."); - minerServer.close(); - log.info("Pool server stop."); - minerManager.stop(); - log.info("Miner manager stop."); - awardManager.stop(); - // 3. 数据层关闭 // TODO 关闭checkmain线程 blockchain.stopCheckMain(); diff --git a/src/main/java/io/xdag/Launcher.java b/src/main/java/io/xdag/Launcher.java index 58924241a..34ef91557 100644 --- a/src/main/java/io/xdag/Launcher.java +++ b/src/main/java/io/xdag/Launcher.java @@ -100,22 +100,6 @@ private static synchronized void shutdownHook() { LogManager.shutdown(); } - public static void logPoolInfo(Config config) { - log.info( - "Xdag Node IP Address:[{}:{}], Xdag Pool Service IP Address:[{}:{}],Configure:miner[{}],maxip[{}],maxconn[{}],fee[{}],reward[{}],direct[{}],fun[{}]", - config.getNodeSpec().getNodeIp(), - config.getNodeSpec().getNodePort(), - config.getPoolSpec().getPoolIp(), - config.getPoolSpec().getPoolPort(), - config.getPoolSpec().getGlobalMinerLimit(), - config.getPoolSpec().getMaxConnectPerIp(), - config.getPoolSpec().getMaxMinerPerAccount(), - config.getPoolSpec().getPoolRation(), - config.getPoolSpec().getRewardRation(), - config.getPoolSpec().getDirectRation(), - config.getPoolSpec().getFundRation()); - } - /** * Adds a supported option. */ @@ -141,7 +125,7 @@ protected CommandLine parseOptions(String[] args) throws ParseException { return cmd; } - protected Config buildConfig(String[] args) throws Exception { + protected Config buildConfig(String[] args) { Config config = null; for (String arg : args) { if ("-d".equals(arg)) { @@ -159,10 +143,6 @@ protected Config buildConfig(String[] args) throws Exception { } config.changePara(args); config.setDir(); - logPoolInfo(config); - - // init keys - config.initKeys(); return config; } diff --git a/src/main/java/io/xdag/mine/message/NewBalanceMessage.java b/src/main/java/io/xdag/Network.java similarity index 57% rename from src/main/java/io/xdag/mine/message/NewBalanceMessage.java rename to src/main/java/io/xdag/Network.java index fa24c0dba..adb7dbb48 100644 --- a/src/main/java/io/xdag/mine/message/NewBalanceMessage.java +++ b/src/main/java/io/xdag/Network.java @@ -21,46 +21,56 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag; -package io.xdag.mine.message; +import java.util.HashMap; +import java.util.Map; -import static io.xdag.net.message.XdagMessageCodes.NEW_BALANCE; +public enum Network { -import io.xdag.core.XdagField; -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; + MAINNET((byte) 0, "mainnet"), -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; + TESTNET((byte) 1, "testnet"), -public class NewBalanceMessage extends Message { + DEVNET((byte) 2, "devnet"); - private final XdagField xdagField; - - public NewBalanceMessage(MutableBytes encoded) { - super(encoded); - this.xdagField = new XdagField(encoded); + Network(byte id, String label) { + this.id = id; + this.label = label; } - @Override - public Bytes getEncoded() { - return xdagField.getData(); + private final byte id; + private final String label; + + private static final Map labels = new HashMap<>(); + private static final Map ids = new HashMap<>(); + + static { + for (Network net : Network.values()) { + labels.put(net.label, net); + ids.put(net.id, net); + } } - @Override - public Class getAnswerMessage() { - return null; + public byte id() { + return id; } - @Override - public XdagMessageCodes getCommand() { - return NEW_BALANCE; + public String label() { + return label; } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); + return label; } + + public static Network of(byte networkId) { + return ids.get(networkId); + } + + public static Network of(String label) { + return labels.get(label); + } + } diff --git a/src/main/java/io/xdag/cli/Commands.java b/src/main/java/io/xdag/cli/Commands.java index f4364671f..a4b6e64ae 100644 --- a/src/main/java/io/xdag/cli/Commands.java +++ b/src/main/java/io/xdag/cli/Commands.java @@ -29,11 +29,7 @@ import com.google.common.collect.Sets; import io.xdag.Kernel; import io.xdag.core.*; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerCalculate; -import io.xdag.mine.miner.MinerStates; -import io.xdag.net.node.Node; +import io.xdag.net.Channel; import io.xdag.utils.BasicUtils; import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; @@ -49,7 +45,6 @@ import java.math.BigDecimal; import java.math.BigInteger; -import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -389,11 +384,6 @@ public void connect(String server, int port) { kernel.getNodeMgr().doConnect(server, port); } - public void connectbylibp2p(String server, int port, String ip) { - // 连接格式 ("/ip4/192.168.3.5/tcp/11112/ipfs/16Uiu2HAmRfT8vNbCbvjQGsfqWUtmZvrj5y8XZXiyUz6HVSqZW8gy") - kernel.getLibp2pNetwork().dail("/ip4/" + server + "/tcp/" + port + "/ipfs/" + ip.replaceAll(":", "")); - } - /** * Query block by hash * @@ -567,19 +557,11 @@ public void stop() { } public String listConnect() { - Map map = kernel.getNodeMgr().getActiveNode(); + List channelList = kernel.getChannelMgr().getActiveChannels(); StringBuilder stringBuilder = new StringBuilder(); - for (Map.Entry entry : map.entrySet()) { - Node node = entry.getKey(); - stringBuilder - .append(node.getAddress()) - .append(" ") - .append(map.get(node) == null ? null : XdagTime.format(new Date(map.get(node)))) - .append(" ") - .append(node.getStat().Inbound.get()) - .append(" in/") - .append(node.getStat().Outbound.get()) - .append(" out").append(System.getProperty("line.separator")); + for (Channel channel : channelList) { + stringBuilder.append(channel).append(" ") + .append(System.getProperty("line.separator")); } return stringBuilder.toString(); @@ -596,51 +578,10 @@ public String keygen() return "Key " + (size - 1) + " generated and set as default,now key size is:" + size; } - public String miners() { - Miner poolMiner = kernel.getPoolMiner(); - StringBuilder sbd = new StringBuilder(); - sbd.append("fee:").append(toBase58(poolMiner.getAddressHashByte())).append("\n"); - if (kernel.getMinerManager().getActivateMiners().size() == 0) { - sbd.append(" without activate miners"); - } else { - for (Miner miner : kernel.getMinerManager().getActivateMiners().values()) { - if (miner.getMinerStates() == MinerStates.MINER_ACTIVE) { - sbd.append(MinerCalculate.minerStats(miner)); - } - } - } - return sbd.toString(); - } - public String state() { return kernel.getXdagState().toString(); } - public String disConnectMinerChannel(String command) { - // TODO: 2020/6/13 判断输入的ip地址是否是合法的 端口 然后找到特定的channel 断开连接 - if (StringUtils.equals("all", command)) { - Map channels = kernel.getMinerManager().getActivateMinerChannels(); - for (MinerChannel channel : channels.values()) { - channel.dropConnection(); - } - return "disconnect all channels..."; - } else { - String[] args = command.split(":"); - try { - InetSocketAddress host = new InetSocketAddress(args[0], Integer.parseInt(args[1])); - MinerChannel channel = kernel.getMinerManager().getChannelByHost(host); - if (channel != null) { - channel.dropConnection(); - return "disconnect a channel:" + command; - } else { - return "Can't find the corresponding channel, please check"; - } - } catch (Exception e) { - return "Argument is incorrect."; - } - } - } - public String balanceMaxXfer() { return getBalanceMaxXfer(kernel); } diff --git a/src/main/java/io/xdag/cli/Shell.java b/src/main/java/io/xdag/cli/Shell.java index c7853f4b0..6f93ebfa6 100644 --- a/src/main/java/io/xdag/cli/Shell.java +++ b/src/main/java/io/xdag/cli/Shell.java @@ -78,11 +78,11 @@ public Shell() { commandExecute.put("stats", new CommandMethods(this::processStats, this::defaultCompleter)); commandExecute.put("xfer", new CommandMethods(this::processXfer, this::defaultCompleter)); commandExecute.put("xfertonew", new CommandMethods(this::processXferToNew, this::defaultCompleter)); - commandExecute.put("miners", new CommandMethods(this::processMiners, this::defaultCompleter)); +// commandExecute.put("miners", new CommandMethods(this::processMiners, this::defaultCompleter)); // commandExecute.put("run", new CommandMethods(this::processRun, this::defaultCompleter)); commandExecute.put("keygen", new CommandMethods(this::processKeygen, this::defaultCompleter)); commandExecute.put("net", new CommandMethods(this::processNet, this::defaultCompleter)); - commandExecute.put("disconnect", new CommandMethods(this::processDisconnect, this::defaultCompleter)); +// commandExecute.put("disconnect", new CommandMethods(this::processDisconnect, this::defaultCompleter)); commandExecute.put("ttop", new CommandMethods(this::processTtop, this::defaultCompleter)); commandExecute.put("terminate", new CommandMethods(this::processTerminate, this::defaultCompleter)); commandExecute.put("address", new CommandMethods(this::processAddress, this::defaultCompleter)); @@ -121,7 +121,7 @@ private void processAddress(CommandInput input) { throw new Options.HelpException(opt.usage()); } - if (argv.size() == 0) { + if (argv.isEmpty()) { println("Need hash or address"); return; } @@ -185,7 +185,7 @@ private void processAccount(CommandInput input) { throw new Options.HelpException(opt.usage()); } int num = DEFAULT_LIST_NUM; - if (argv.size() > 0 && NumberUtils.isDigits(argv.get(0))) { + if (!argv.isEmpty() && NumberUtils.isDigits(argv.get(0))) { num = NumberUtils.toInt(argv.get(0)); } println(commands.account(num)); @@ -206,7 +206,7 @@ private void processBalance(CommandInput input) { throw new Options.HelpException(opt.usage()); } List argv = opt.args(); - println(commands.balance(argv.size() > 0 ? argv.get(0) : null)); + println(commands.balance(!argv.isEmpty() ? argv.get(0) : null)); } catch (Exception e) { saveException(e); } @@ -226,7 +226,7 @@ private void processBlock(CommandInput input) { throw new Options.HelpException(opt.usage()); } - if (argv.size() == 0) { + if (argv.isEmpty()) { println("Need hash or address"); return; } @@ -283,7 +283,7 @@ private void processMainBlocks(CommandInput input) { throw new Options.HelpException(opt.usage()); } int num = DEFAULT_LIST_NUM; - if (argv.size() > 0 && NumberUtils.isDigits(argv.get(0))) { + if (!argv.isEmpty() && NumberUtils.isDigits(argv.get(0))) { num = NumberUtils.toInt(argv.get(0)); } println(commands.mainblocks(num)); @@ -305,7 +305,7 @@ private void processMinedblocks(CommandInput input) { throw new Options.HelpException(opt.usage()); } int num = DEFAULT_LIST_NUM; - if (argv.size() > 0 && NumberUtils.isDigits(argv.get(0))) { + if (!argv.isEmpty() && NumberUtils.isDigits(argv.get(0))) { num = NumberUtils.toInt(argv.get(0)); } println(commands.minedBlocks(num)); @@ -396,24 +396,6 @@ private void processXfer(CommandInput input) { } } - private void processMiners(CommandInput input) { - final String[] usage = { - "miners - for pool, print list of recent connected miners", - "Usage: miners ", - " -? --help Show help", - }; - try { - Options opt = parseOptions(usage, input.args()); - if (opt.isSet("help")) { - throw new Options.HelpException(opt.usage()); - } - println(commands.miners()); - } catch (Exception e) { - saveException(e); - } - } - - private void processKeygen(CommandInput input) { final String[] usage = { "keygen - generate new private/public key pair and set it by default", @@ -439,7 +421,6 @@ private void processNet(CommandInput input) { " -? --help Show help", " -l --list list connections", " -c --connect=IP:PORT connect to this host", - " -p --plibp2p=IP:PORT:ID connect to this host by libp2p", }; try { Options opt = parseOptions(usage, input.args()); @@ -461,48 +442,6 @@ private void processNet(CommandInput input) { println("Node ip:port Error"); } } - if (opt.isSet("plibp2p")) { - println("connect to :" + opt.get("plibp2p")); - Matcher m = p.matcher(opt.get("plibp2p")); - if (m.matches()) { - String host = m.group(1); - int port = Integer.parseInt(m.group(2)); - String ip = m.group(3); - commands.connectbylibp2p(host, port, ip); - } else { - println("Node ip:port Error"); - } - } - } catch (Exception e) { - saveException(e); - } - } - - private void processDisconnect(CommandInput input) { - final String[] usage = { - "disconnect - disconnect all connections or specified miners", - "Usage: disconnect [OPTIONS]", - " -? --help Show help", - " -a --all all miners", - " -o --address=ADDRESS [ADDRESS] is the miners' address", - " -i --ip=IP [IP] is the miners' IP", - }; - try { - Options opt = parseOptions(usage, input.args()); - if (opt.isSet("help")) { - throw new Options.HelpException(opt.usage()); - } - if (opt.isSet("all")) { - println(commands.disConnectMinerChannel("all")); - return; - } - if (opt.isSet("address")) { - println(commands.disConnectMinerChannel(opt.get("address"))); - return; - } - if (opt.isSet("ip")) { - println(commands.disConnectMinerChannel(opt.get("ip"))); - } } catch (Exception e) { saveException(e); } diff --git a/src/main/java/io/xdag/cli/XdagCli.java b/src/main/java/io/xdag/cli/XdagCli.java index e66adec75..2a434232d 100644 --- a/src/main/java/io/xdag/cli/XdagCli.java +++ b/src/main/java/io/xdag/cli/XdagCli.java @@ -251,6 +251,7 @@ protected void start() throws IOException { startKernel(getConfig(), wallet); } catch (Exception e) { System.err.println("Uncaught exception during kernel startup:" + e.getMessage()); + e.printStackTrace(); exit(-1); } } diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index 4fbf4c496..4baa0ac3b 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -27,31 +27,36 @@ import com.google.common.collect.Lists; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigObject; + +import io.xdag.Network; import io.xdag.config.spec.AdminSpec; import io.xdag.config.spec.NodeSpec; -import io.xdag.config.spec.PoolSpec; import io.xdag.config.spec.RPCSpec; import io.xdag.config.spec.RandomxSpec; import io.xdag.config.spec.SnapshotSpec; import io.xdag.config.spec.WalletSpec; import io.xdag.core.XAmount; import io.xdag.core.XdagField; -import io.xdag.crypto.DnetKeys; +import io.xdag.net.Capability; +import io.xdag.net.CapabilityTreeSet; +import io.xdag.net.message.MessageCode; import io.xdag.rpc.modules.ModuleDescription; -import java.io.InputStream; import java.net.InetSocketAddress; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; + import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; + +import org.apache.commons.lang3.SystemUtils; @Slf4j @Getter @Setter -public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, WalletSpec, RPCSpec, SnapshotSpec, RandomxSpec { +public class AbstractConfig implements Config, AdminSpec, NodeSpec, WalletSpec, RPCSpec, SnapshotSpec, RandomxSpec { protected String configName; @@ -62,32 +67,33 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa protected int telnetPort = 7001; protected String telnetPassword; - // ========================= - // Mining Pool spec - // ========================= - protected String poolIp; - protected int poolPort; - protected String poolTag; - protected double poolRation; - protected double rewardRation; - protected double fundRation; - protected double directRation; - protected String fundAddress; - - protected int globalMinerLimit; - protected int globalMinerChannelLimit; - protected int maxMinerPerAccount; - protected int maxConnectPerIp; - protected int maxShareCountPerChannel = 20; protected int awardEpoch = 0xf; protected int waitEpoch = 20; // ========================= - // Node spec + // Network // ========================= + protected Network network; + protected short networkVersion; + protected int netMaxOutboundConnections = 128; + protected int netMaxInboundConnections = 512; + protected int netMaxInboundConnectionsPerIp = 5; + protected int netMaxMessageQueueSize = 4096; + protected int netMaxFrameBodySize = 128 * 1024; + protected int netMaxPacketSize = 16 * 1024 * 1024; + protected int netRelayRedundancy = 8; + protected int netHandshakeExpiry = 5 * 60 * 1000; + protected int netChannelIdleTimeout = 2 * 60 * 1000; + + protected Set netPrioritizedMessages = new HashSet<>(Arrays.asList( + MessageCode.NEW_BLOCK, + MessageCode.BLOCK_REQUEST, + MessageCode.BLOCKS_REQUEST)); + protected String nodeIp; protected int nodePort; + protected String nodeTag; protected int maxConnections = 1024; protected int maxInboundConnectionsPerIp = 8; protected int connectionTimeout = 10000; @@ -112,19 +118,9 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa protected String walletKeyFile; protected int TTL = 5; - protected byte[] dnetKeyBytes = new byte[2048]; - protected DnetKeys xKeys; protected List whiteIPList = Lists.newArrayList(); - // ========================= - // Libp2p spec - // ========================= - protected int libp2pPort; - protected boolean isBootnode; - protected String libp2pPrivkey; - protected List bootnodes = Lists.newArrayList(); - // ========================= // Wallet spec // ========================= @@ -139,7 +135,6 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa protected long apolloForkHeight; protected XAmount apolloForkAmount; - // ========================= // Xdag RPC modules // ========================= @@ -162,9 +157,11 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa // ========================= protected boolean flag; - protected AbstractConfig(String rootDir, String configName) { + protected AbstractConfig(String rootDir, String configName, Network network, short networkVersion) { this.rootDir = rootDir; this.configName = configName; + this.network = network; + this.networkVersion = networkVersion; getSetting(); setDir(); @@ -177,21 +174,6 @@ public void setDir() { netDBDir = getRootDir() + "/netdb.txt"; } - public void initKeys() throws Exception { - InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("dnet_keys.bin"); - if (inputStream == null) { - throw new RuntimeException("can not find dnet_key.bin file."); - } else { - xKeys = new DnetKeys(); - byte[] data = new byte[3072]; - IOUtils.read(inputStream, data); - System.arraycopy(data, 0, xKeys.prv, 0, 1024); - System.arraycopy(data, 1024, xKeys.pub, 0, 1024); - System.arraycopy(data, 2048, xKeys.sect0_encoded, 0, 512); - System.arraycopy(data, 2048 + 512, xKeys.sect0, 0, 512); - } - } - @Override public RPCSpec getRPCSpec() { return this; @@ -208,8 +190,37 @@ public RandomxSpec getRandomxSpec() { } @Override - public PoolSpec getPoolSpec() { - return this; + public Network getNetwork() { + return this.network; + } + + @Override + public short getNetworkVersion() { + return this.networkVersion; + } + + @Override + public String getNodeTag() { + return this.nodeTag; + } + + @Override + public Set getNetPrioritizedMessages() { + return this.netPrioritizedMessages; + } + + @Override + public String getClientId() { + return String.format("%s/v%s-%s/%s", + Constants.CLIENT_NAME, + Constants.CLIENT_VERSION, + SystemUtils.OS_NAME, + SystemUtils.OS_ARCH); + } + + @Override + public CapabilityTreeSet getClientCapabilities() { + return CapabilityTreeSet.of(Capability.FULL_NODE, Capability.LIGHT_NODE); } @Override @@ -234,18 +245,9 @@ public void getSetting() { telnetPort = config.hasPath("admin.telnet.port")?config.getInt("admin.telnet.port"):6001; telnetPassword = config.getString("admin.telnet.password"); - poolIp = config.hasPath("pool.ip")?config.getString("pool.ip"):"127.0.0.1"; - poolPort = config.hasPath("pool.port")?config.getInt("pool.port"):7001; - poolTag = config.hasPath("pool.tag")?config.getString("pool.tag"):"xdagj"; - - poolRation = config.getInt("pool.poolRation"); - rewardRation = config.getInt("pool.rewardRation"); - fundRation = config.getInt("pool.fundRation"); - directRation = config.getInt("pool.directRation"); - fundAddress = config.hasPath("pool.fundAddress")?config.getString("pool.fundAddress"):"FQglVQtb60vQv2DOWEUL7yh3smtj7g1s"; - nodeIp = config.hasPath("node.ip")?config.getString("node.ip"):"127.0.0.1"; nodePort = config.hasPath("node.port")?config.getInt("node.port"):8001; + nodeTag = config.hasPath("node.tag")?config.getString("node.tag"):"xdagj"; maxInboundConnectionsPerIp = config.getInt("node.maxInboundConnectionsPerIp"); enableTxHistory = config.hasPath("node.transaction.history.enable")?config.getBoolean("node.transaction.history.enable"):false; enableGenerateBlock = config.hasPath("node.generate.block.enable") && config.getBoolean("node.generate.block.enable"); @@ -259,20 +261,6 @@ public void getSetting() { whiteIPList.add(new InetSocketAddress(ip,port)); } - libp2pPort = config.getInt("node.libp2p.port"); - libp2pPrivkey = config.getString("node.libp2p.privkey"); - isBootnode = config.getBoolean("node.libp2p.isbootnode"); - - List bootnodeList = config.getStringList("node.libp2p.bootnode"); - if (bootnodeList != null) { - bootnodes.addAll(bootnodeList); - } - - globalMinerLimit = config.getInt("miner.globalMinerLimit"); - globalMinerChannelLimit = config.getInt("miner.globalMinerChannelLimit"); - maxConnectPerIp = config.getInt("miner.maxConnectPerIp"); - maxMinerPerAccount = config.getInt("miner.maxMinerPerAccount"); - // rpc rpcEnabled = config.hasPath("rpc.enabled")?config.getBoolean("rpc.enabled"):false; if (rpcEnabled) { @@ -308,16 +296,9 @@ public void changePara(String[] args) { i++; this.changeNode(args[i]); break; - case "-P": - i++; - this.changePoolPara(args[i]); - break; case "-r": // todo only load block but no run break; - case "-tag": - this.poolTag = StringUtils.substring(args[i + 1], 0, 31); - break; case "-d": case "-t": // only devnet or testnet @@ -334,29 +315,13 @@ public void changeNode(String host) { this.nodePort = Integer.parseInt(args[1]); } - /** - * 设置矿池的分配奖励 - */ - public void changePoolPara(String para) { - String[] args = para.split(":"); - if (args.length != 9) { - throw new IllegalArgumentException("Illegal instruction"); - } - this.setPoolIp(args[0]); - this.setPoolPort(Integer.parseInt(args[1])); - this.globalMinerChannelLimit = Integer.parseInt(args[2]); - this.maxConnectPerIp = Integer.parseInt(args[3]); - this.maxMinerPerAccount = Integer.parseInt(args[4]); - this.poolRation = Double.parseDouble(args[5]); - this.rewardRation = Double.parseDouble(args[6]); - this.directRation = Double.parseDouble(args[7]); - this.fundRation = Double.parseDouble(args[8]); + @Override + public int getNetMaxFrameBodySize() { + return this.netMaxFrameBodySize; } @Override - public boolean isBootnode() { - return this.isBootnode; - } + public int getNetMaxPacketSize() { return this.netMaxPacketSize; } @Override public int getMaxInboundConnectionsPerIp() { diff --git a/src/main/java/io/xdag/config/Config.java b/src/main/java/io/xdag/config/Config.java index 72a2954b5..de9a9ea9e 100644 --- a/src/main/java/io/xdag/config/Config.java +++ b/src/main/java/io/xdag/config/Config.java @@ -26,13 +26,13 @@ import io.xdag.config.spec.AdminSpec; import io.xdag.config.spec.NodeSpec; -import io.xdag.config.spec.PoolSpec; import io.xdag.config.spec.RPCSpec; import io.xdag.config.spec.RandomxSpec; import io.xdag.config.spec.SnapshotSpec; import io.xdag.config.spec.WalletSpec; import io.xdag.core.XAmount; import io.xdag.core.XdagField; +import io.xdag.net.CapabilityTreeSet; /** * The Xdag blockchain configurations. @@ -44,16 +44,15 @@ public interface Config { */ String getConfigName(); + String getClientId(); + + CapabilityTreeSet getClientCapabilities(); + /** * Config Root Dir. */ String getRootDir(); - /** - * Pool Specification. - */ - PoolSpec getPoolSpec(); - /** * Node Specification. */ @@ -83,8 +82,6 @@ public interface Config { void setDir(); - void initKeys() throws Exception; - // rpc RPCSpec getRPCSpec(); diff --git a/src/main/java/io/xdag/config/Constants.java b/src/main/java/io/xdag/config/Constants.java index 89dd0cfaf..eee651fbf 100644 --- a/src/main/java/io/xdag/config/Constants.java +++ b/src/main/java/io/xdag/config/Constants.java @@ -73,6 +73,9 @@ public class Constants { public static final String WALLET_FILE_NAME = "wallet.data"; + + public static final String CLIENT_NAME = "xdagj"; + public static final String CLIENT_VERSION = System.getProperty("xdagj.version"); /** @@ -88,4 +91,8 @@ public enum MessageType { NEW_LINK } + public static final short MAINNET_VERSION = 0; + public static final short TESTNET_VERSION = 0; + public static final short DEVNET_VERSION = 0; + } diff --git a/src/main/java/io/xdag/config/DevnetConfig.java b/src/main/java/io/xdag/config/DevnetConfig.java index 55076ed47..65865adc6 100644 --- a/src/main/java/io/xdag/config/DevnetConfig.java +++ b/src/main/java/io/xdag/config/DevnetConfig.java @@ -29,12 +29,13 @@ import org.apache.commons.lang3.StringUtils; import org.apache.tuweni.units.bigints.UInt64; +import io.xdag.Network; import io.xdag.core.XAmount; public class DevnetConfig extends AbstractConfig { public DevnetConfig() { - super("devnet", "xdag-devnet"); + super("devnet", "xdag-devnet", Network.DEVNET, Constants.DEVNET_VERSION); this.whitelistUrl = StringUtils.EMPTY; this.waitEpoch = 1; this.xdagEra = 0x16900000000L; diff --git a/src/main/java/io/xdag/config/MainnetConfig.java b/src/main/java/io/xdag/config/MainnetConfig.java index a655f16dc..eea35d649 100644 --- a/src/main/java/io/xdag/config/MainnetConfig.java +++ b/src/main/java/io/xdag/config/MainnetConfig.java @@ -27,12 +27,15 @@ import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD; import org.apache.tuweni.units.bigints.UInt64; + +import io.xdag.Network; import io.xdag.core.XAmount; public class MainnetConfig extends AbstractConfig { public MainnetConfig() { - super("mainnet", "xdag-mainnet"); + super("mainnet", "xdag-mainnet", Network.MAINNET, Constants.MAINNET_VERSION); + this.network = Network.MAINNET; this.whitelistUrl = "https://raw.githubusercontent.com/XDagger/xdag/master/client/netdb-white.txt"; this.xdagEra = 0x16940000000L; this.mainStartAmount = XAmount.ofXAmount(UInt64.valueOf(1L << 42).toLong()); diff --git a/src/main/java/io/xdag/config/RandomXConstants.java b/src/main/java/io/xdag/config/RandomXConstants.java index 0d37a36bd..a4881597d 100644 --- a/src/main/java/io/xdag/config/RandomXConstants.java +++ b/src/main/java/io/xdag/config/RandomXConstants.java @@ -26,9 +26,6 @@ public class RandomXConstants { - /** - * RandomX - **/ public static final long SEEDHASH_EPOCH_BLOCKS = 4096; public static final long SEEDHASH_EPOCH_LAG = 128; public static final long RANDOMX_FORK_HEIGHT = 1540096; diff --git a/src/main/java/io/xdag/config/TestnetConfig.java b/src/main/java/io/xdag/config/TestnetConfig.java index 1d383b74b..89b83e1c3 100644 --- a/src/main/java/io/xdag/config/TestnetConfig.java +++ b/src/main/java/io/xdag/config/TestnetConfig.java @@ -27,12 +27,14 @@ import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD_TEST; import org.apache.tuweni.units.bigints.UInt64; + +import io.xdag.Network; import io.xdag.core.XAmount; public class TestnetConfig extends AbstractConfig { public TestnetConfig() { - super("testnet", "xdag-testnet"); + super("testnet", "xdag-testnet", Network.TESTNET, Constants.TESTNET_VERSION); this.whitelistUrl = "https://raw.githubusercontent.com/XDagger/xdag/master/client/netdb-white-testnet.txt"; // testnet wait 1 epoch this.waitEpoch = 1; diff --git a/src/main/java/io/xdag/config/spec/NodeSpec.java b/src/main/java/io/xdag/config/spec/NodeSpec.java index 2f9f1d425..5fee5e17a 100644 --- a/src/main/java/io/xdag/config/spec/NodeSpec.java +++ b/src/main/java/io/xdag/config/spec/NodeSpec.java @@ -24,16 +24,38 @@ package io.xdag.config.spec; -import io.xdag.crypto.DnetKeys; +import io.xdag.Network; +import io.xdag.net.message.MessageCode; + import java.net.InetSocketAddress; import java.util.List; +import java.util.Set; /** * The Node Specifications */ public interface NodeSpec { - // dnet + Network getNetwork(); + + short getNetworkVersion(); + + String getNodeTag(); + + int getWaitEpoch(); + + int getNetMaxMessageQueueSize(); + + int getNetHandshakeExpiry(); + + Set getNetPrioritizedMessages(); + + int getNetMaxInboundConnectionsPerIp(); + + int getNetMaxInboundConnections(); + + int getNetChannelIdleTimeout(); + String getNodeIp(); int getNodePort(); @@ -44,7 +66,7 @@ public interface NodeSpec { int getConnectionReadTimeout(); - DnetKeys getXKeys(); + int getConnectionTimeout(); int getTTL(); @@ -52,15 +74,6 @@ public interface NodeSpec { void setWhiteIPList(List list); - // libp2p - boolean isBootnode(); - - List getBootnodes(); - - int getLibp2pPort(); - - String getLibp2pPrivkey(); - String getStoreDir(); // Store @@ -80,10 +93,9 @@ public interface NodeSpec { boolean isStoreFromBackup(); - /** - * 用于测试加载已有区块数据 从C版本生成的数据 请将所需要的数据放在该目录下 - */ - String getOriginStoreDir(); + int getNetMaxFrameBodySize(); + + int getNetMaxPacketSize(); // White List String getWhitelistUrl(); diff --git a/src/main/java/io/xdag/consensus/PoW.java b/src/main/java/io/xdag/consensus/PoW.java index 31a703120..df5e7ef9c 100644 --- a/src/main/java/io/xdag/consensus/PoW.java +++ b/src/main/java/io/xdag/consensus/PoW.java @@ -24,8 +24,7 @@ package io.xdag.consensus; -import io.xdag.mine.MinerChannel; -import io.xdag.net.message.Message; +import org.apache.tuweni.bytes.MutableBytes; public interface PoW { @@ -47,11 +46,8 @@ public interface PoW { boolean isRunning(); /** - * Receive and process shares sent by miners - * - * @param channel minerchannel - * @param msg share + * Receive and process shares sent by pool */ - void receiveNewShare(MinerChannel channel, Message msg); + void receiveNewShare(MutableBytes data, long time); } diff --git a/src/main/java/io/xdag/consensus/SyncManager.java b/src/main/java/io/xdag/consensus/SyncManager.java index 65fd607bc..7e4f8f4dd 100644 --- a/src/main/java/io/xdag/consensus/SyncManager.java +++ b/src/main/java/io/xdag/consensus/SyncManager.java @@ -33,12 +33,15 @@ import io.xdag.core.*; import io.xdag.db.TransactionHistoryStore; import io.xdag.net.Channel; -import io.xdag.net.libp2p.discovery.DiscoveryPeer; -import io.xdag.net.manager.XdagChannelManager; +import io.xdag.net.ChannelManager; +import io.xdag.net.Peer; +import io.xdag.net.node.Node; import io.xdag.utils.XdagTime; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.commons.lang3.time.FastDateFormat; import org.apache.tuweni.bytes.Bytes32; @@ -72,9 +75,7 @@ public class SyncManager { private AtomicLong importIdleTime = new AtomicLong(); private AtomicBoolean syncDone = new AtomicBoolean(false); private AtomicBoolean isUpdateXdagStats = new AtomicBoolean(false); - private XdagChannelManager channelMgr; - private ScheduledFuture connectlibp2pFuture; - private Set hadConnectnode = new HashSet<>(); + private ChannelManager channelMgr; // 监听是否需要自己启动 @@ -147,7 +148,7 @@ private void checkState() { public boolean isTimeToStart() { boolean res = false; Config config = kernel.getConfig(); - int waitEpoch = config.getPoolSpec().getWaitEpoch(); + int waitEpoch = config.getNodeSpec().getWaitEpoch(); if (!isSync() && !isSyncOld() && (XdagTime.getCurrentEpoch() > kernel.getStartEpoch() + waitEpoch)) { res = true; } @@ -171,8 +172,9 @@ public ImportResult importBlock(BlockWrapper blockWrapper) { } if (!blockWrapper.isOld() && (importResult == IMPORTED_BEST || importResult == IMPORTED_NOT_BEST)) { - if (blockWrapper.getRemoteNode() == null - || !blockWrapper.getRemoteNode().equals(kernel.getClient().getNode())) { + Peer blockPeer = blockWrapper.getRemotePeer(); + Node node = kernel.getClient().getNode(); + if (blockPeer == null || !StringUtils.equals(blockPeer.getIp(), node.getIp()) || blockPeer.getPort() != node.getPort()) { if (blockWrapper.getTtl() > 0) { distributeBlock(blockWrapper); } @@ -192,10 +194,9 @@ public synchronized ImportResult validateAndAddNewBlock(BlockWrapper blockWrappe log.debug("push block:{}, NO_PARENT {}", blockWrapper.getBlock().getHashLow(), result); List channels = channelMgr.getActiveChannels(); for (Channel channel : channels) { - if (channel.getNode().equals(blockWrapper.getRemoteNode())) { - channel.getXdag().sendGetBlock(result.getHashlow(), blockWrapper.isOld()); - - } + //if (channel.getRemotePeer().equals(blockWrapper.getRemotePeer())) { + channel.getP2pHandler().sendGetBlock(result.getHashlow(), blockWrapper.isOld()); + //} } } @@ -258,8 +259,6 @@ public boolean syncPushBlock(BlockWrapper blockWrapper, Bytes32 hashLow) { /** * 根据接收到的区块,将子区块释放 - * - * @param blockWrapper 接收到的区块 */ public void syncPopBlock(BlockWrapper blockWrapper) { Block block = blockWrapper.getBlock(); @@ -282,9 +281,11 @@ public void syncPopBlock(BlockWrapper blockWrapper) { importResult.getHashlow().toHexString()); List channels = channelMgr.getActiveChannels(); for (Channel channel : channels) { - if (channel.getNode().equals(bw.getRemoteNode())) { - channel.getXdag().sendGetBlock(importResult.getHashlow(), blockWrapper.isOld()); - } +// Peer remotePeer = channel.getRemotePeer(); +// Peer blockPeer = bw.getRemotePeer(); + //if (StringUtils.equals(remotePeer.getIp(), blockPeer.getIp()) && remotePeer.getPort() == blockPeer.getPort() ) { + channel.getP2pHandler().sendGetBlock(importResult.getHashlow(), blockWrapper.isOld()); + //} } } } @@ -317,13 +318,15 @@ public void makeSyncDone() { log.info("sync done, the last main block number = {}", blockchain.getXdagStats().nmain); kernel.getSync().setStatus(XdagSync.Status.SYNC_DONE); - // sync done, the remaining history is batch written. - txHistoryStore.batchSaveTxHistory(null); + if(config.getEnableTxHistory() && txHistoryStore != null) { + // sync done, the remaining history is batch written. + txHistoryStore.batchSaveTxHistory(null); + } if (config.getEnableGenerateBlock()) { log.info("start pow at:" + FastDateFormat.getInstance("yyyy-MM-dd 'at' HH:mm:ss z").format(new Date())); // check main chain - kernel.getMinerServer().start(); +// kernel.getMinerServer().start(); kernel.getPow().start(); } else { log.info("A non-mining node, will not generate blocks."); diff --git a/src/main/java/io/xdag/consensus/Task.java b/src/main/java/io/xdag/consensus/Task.java index 29af8275d..9357f72eb 100644 --- a/src/main/java/io/xdag/consensus/Task.java +++ b/src/main/java/io/xdag/consensus/Task.java @@ -29,22 +29,17 @@ import lombok.Getter; import lombok.Setter; +@Getter +@Setter public class Task implements Cloneable { - @Getter - @Setter + private XdagField[] task; - @Getter - @Setter private long taskTime; - @Getter - @Setter private long taskIndex; - @Getter - @Setter private XdagSha256Digest digest; @Override diff --git a/src/main/java/io/xdag/consensus/XdagPow.java b/src/main/java/io/xdag/consensus/XdagPow.java index a8dfe6dfa..8c76b432a 100644 --- a/src/main/java/io/xdag/consensus/XdagPow.java +++ b/src/main/java/io/xdag/consensus/XdagPow.java @@ -38,17 +38,10 @@ import io.xdag.listener.BlockMessage; import io.xdag.listener.Listener; import io.xdag.listener.PretopMessage; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.manager.AwardManager; -import io.xdag.mine.manager.MinerManager; -import io.xdag.mine.miner.MinerCalculate; -import io.xdag.mine.randomx.RandomX; -import io.xdag.mine.randomx.RandomXMemory; -import io.xdag.net.manager.XdagChannelManager; -import io.xdag.net.message.Message; -import io.xdag.utils.XdagSha256Digest; +import io.xdag.crypto.RandomX; +import io.xdag.crypto.RandomXMemory; +import io.xdag.net.ChannelManager; import io.xdag.utils.XdagTime; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; @@ -57,8 +50,9 @@ import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; + +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; @@ -77,11 +71,9 @@ public class XdagPow implements PoW, Listener, Runnable { protected AtomicReference generateBlock = new AtomicReference<>(); protected AtomicReference minShare = new AtomicReference<>(); protected final AtomicReference minHash = new AtomicReference<>(); - protected XdagChannelManager channelMgr; + protected ChannelManager channelMgr; protected Blockchain blockchain; protected volatile Bytes32 globalPretop; - protected AtomicReference currentTask = new AtomicReference<>(); - protected AtomicLong taskIndex = new AtomicLong(0L); private boolean isWorking = false; @@ -105,11 +97,7 @@ public class XdagPow implements PoW, Listener, Runnable { * 存放的是最小的hash */ protected List minShares = new CopyOnWriteArrayList<>(new ArrayList<>(16)); - /** - * 引入矿工与奖励 - */ - protected AwardManager awardManager; - protected MinerManager minerManager; + protected RandomX randomXUtils; private boolean isRunning = false; @@ -119,8 +107,6 @@ public XdagPow(Kernel kernel) { this.channelMgr = kernel.getChannelMgr(); this.timer = new Timer(); this.broadcaster = new Broadcaster(); - this.minerManager = kernel.getMinerManager(); - this.awardManager = kernel.getAwardManager(); this.randomXUtils = kernel.getRandomx(); } @@ -129,12 +115,10 @@ public void start() { if (!this.isRunning) { this.isRunning = true; - this.minerManager = kernel.getMinerManager(); - // 容器的初始化 for (int i = 0; i < 16; i++) { this.blockHashs.add(null); - this.minShares.add(null); +// this.minShares.add(null); } timerExecutor.execute(timer); @@ -197,34 +181,17 @@ public void newBlock() { public Block generateRandomXBlock(long sendTime) { - // 新增任务 - taskIndex.incrementAndGet(); - Block block = blockchain.createNewBlock(null, null, true, null); block.signOut(kernel.getWallet().getDefKey()); minShare.set(Bytes32.wrap(RandomUtils.nextBytes(32))); block.setNonce(minShare.get()); -// minHash = Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); minHash.set(Bytes32.fromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); - - currentTask.set(createTaskByRandomXBlock(block, sendTime)); - - log.info("current task seed is {}",currentTask.get().getTask()[1].getData().toHexString()); - // 更新poolminer的贡献 - - minerManager.updateTask(currentTask.get()); - awardManager.onNewTask(currentTask.get()); - log.debug("send randomx task to miners"); -// log.debug("Generate RandomX block :{}", BasicUtils.hash2Address(block.getHash())); return block; } public Block generateBlock(long sendTime) { - // 新增任务 - taskIndex.incrementAndGet(); - Block block = blockchain.createNewBlock(null, null, true, null); block.signOut(kernel.getWallet().getDefKey()); @@ -232,15 +199,6 @@ public Block generateBlock(long sendTime) { block.setNonce(minShare.get()); // 初始nonce, 计算minhash但不作为最终hash minHash.set(block.recalcHash()); - - currentTask.set(createTaskByNewBlock(block, sendTime)); - // 发送给矿工 - - // 更新poolminer的贡献 - minerManager.updateTask(currentTask.get()); - awardManager.onNewTask(currentTask.get()); - log.debug("send origin task to Miners"); -// log.debug("Generate block :{}", BasicUtils.hash2Address(block.getHash())); return block; } @@ -258,14 +216,13 @@ public boolean isRunning() { * 每收到一个miner的信息 之后都会在这里进行一次计算 */ @Override - public void receiveNewShare(MinerChannel channel, Message msg) { + public void receiveNewShare(MutableBytes data, long time) { if (!this.isRunning) { return; } - XdagField shareInfo = new XdagField(msg.getEncoded().mutableCopy()); - log.debug("Receive share From PoolChannel, Shareinfo:{}", shareInfo.getData().toHexString()); - onNewShare(shareInfo, channel); + log.debug("Receive Shareinfo From Pool, Shareinfo:{}, time:{}", data.toHexString(), time); + onNewShare(data, time); } public void receiveNewPretop(Bytes pretop) { @@ -282,50 +239,41 @@ public void receiveNewPretop(Bytes pretop) { } } - protected void onNewShare(XdagField shareInfo, MinerChannel channel) { - Task task = currentTask.get(); + protected void onNewShare(MutableBytes data, long taskTime) { +// Task task = currentTask.get(); try { -// log.debug("Receive a share:{} from miner:{} for block:{}",shareInfo.getData(),channel.getAddressHash(),BasicUtils.hash2Address(generateBlock.get().getHash())); Bytes32 hash; // if randomx fork - if (kernel.getRandomx().isRandomxFork(task.getTaskTime())) { + if (randomXUtils.isRandomxFork(taskTime)) { MutableBytes taskData = MutableBytes.create(64); -// currentTask.getTask()[0].getData().copyTo(taskData, 0); - taskData.set(0, task.getTask()[0].getData()); -// shareInfo.getData().reverse().copyTo(taskData, 32); - taskData.set(32, shareInfo.getData().mutableSlice(0,32).reverse()); - hash = Bytes32.wrap(kernel.getRandomx() - .randomXPoolCalcHash(taskData, taskData.size(), task.getTaskTime()).reverse()); + taskData.set(0, data); + taskData.set(32, data.mutableSlice(0,32).reverse()); + hash = Bytes32.wrap(randomXUtils.randomXPoolCalcHash(taskData, taskData.size(), taskTime).reverse()); } else { - XdagSha256Digest digest = new XdagSha256Digest(task.getDigest()); -// hash = Bytes32.wrap(digest.sha256Final(Arrays.reverse(shareInfo.getData().toArray()))); - hash = Bytes32.wrap(digest.sha256Final(shareInfo.getData().reverse())); +// XdagSha256Digest digest = new XdagSha256Digest(task.getDigest()); +// hash = Bytes32.wrap(digest.sha256Final(data.reverse())); + hash = Hash.hashTwice(data.reverse()); } synchronized (minHash) { Bytes32 mh = minHash.get(); if (compareTo(hash.toArray(), 0, 32, mh.toArray(), 0, 32) < 0) { minHash.set(hash); - minShare.set(Bytes32.wrap(shareInfo.getData().reverse())); + minShare.set(Bytes32.wrap(data.reverse())); // put minshare into nonce Block b = generateBlock.get(); b.setNonce(minShare.get()); - //myron - int index = (int) ((currentTask.get().getTaskTime() >> 16) & kernel.getConfig().getPoolSpec() - .getAwardEpoch()); - // int index = (int) ((currentTask.getTaskTime() >> 16) & 7); - minShares.set(index, minShare.get()); - blockHashs.set(index, b.recalcHash()); + //minShares.set(index, minShare.get()); log.debug("New MinHash :" + mh.toHexString()); log.debug("New MinShare :" + minShare.get().toHexString()); } } //update miner state - MinerCalculate.updateMeanLogDiff(channel, currentTask.get(), hash); - MinerCalculate.calculateNopaidShares(kernel.getConfig(), channel, hash, currentTask.get().getTaskTime()); +// MinerCalculate.updateMeanLogDiff(channel, currentTask.get(), hash); +// MinerCalculate.calculateNopaidShares(kernel.getConfig(), channel, hash, currentTask.get().getTaskTime()); } catch (Exception e) { log.error(e.getMessage(), e); } @@ -337,11 +285,10 @@ protected void onTimeout() { isWorking = false; if (b != null) { Block newBlock = new Block(new XdagBlock(b.toBytes())); - log.debug("Broadcast locally generated blockchain, waiting to be verified. block hash = [{}]", - newBlock.getHash().toHexString()); - // add new block, reward miner, and broadcast the new block + log.debug("Broadcast locally generated blockchain, waiting to be verified. block hash = [{}]", newBlock.getHash().toHexString()); + // add new block and broadcast the new block kernel.getBlockchain().tryToConnect(newBlock); - awardManager.addAwardBlock(minShare.get(), newBlock.getHash(), newBlock.getTimestamp()); + BlockWrapper bw = new BlockWrapper(newBlock, kernel.getConfig().getNodeSpec().getTTL()); broadcaster.broadcast(bw); } @@ -373,40 +320,40 @@ private Task createTaskByRandomXBlock(Block block, long sendTime) { newTask.setTask(task); newTask.setTaskTime(XdagTime.getEpoch(sendTime)); - newTask.setTaskIndex(taskIndex.get()); +// newTask.setTaskIndex(taskIndex.get()); return newTask; } - /** - * 创建原始任务 - */ - private Task createTaskByNewBlock(Block block, long sendTime) { - Task newTask = new Task(); - - XdagField[] task = new XdagField[2]; - task[1] = block.getXdagBlock().getField(14); -// byte[] data = new byte[448]; - MutableBytes data = MutableBytes.create(448); - -// System.arraycopy(block.getXdagBlock().getData(), 0, data, 0, 448); - data.set(0, block.getXdagBlock().getData().slice(0, 448)); - - XdagSha256Digest currentTaskDigest = new XdagSha256Digest(); - try { - currentTaskDigest.sha256Update(data); - byte[] state = currentTaskDigest.getState(); - task[0] = new XdagField(MutableBytes.wrap(state)); - currentTaskDigest.sha256Update(block.getXdagBlock().getField(14).getData()); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - newTask.setTask(task); - newTask.setTaskTime(XdagTime.getEpoch(sendTime)); - newTask.setTaskIndex(taskIndex.get()); - newTask.setDigest(currentTaskDigest); - return newTask; - } +// /** +// * 创建原始任务 +// */ +// private Task createTaskByNewBlock(Block block, long sendTime) { +// Task newTask = new Task(); +// +// XdagField[] task = new XdagField[2]; +// task[1] = block.getXdagBlock().getField(14); +//// byte[] data = new byte[448]; +// MutableBytes data = MutableBytes.create(448); +// +//// System.arraycopy(block.getXdagBlock().getData(), 0, data, 0, 448); +// data.set(0, block.getXdagBlock().getData().slice(0, 448)); +// +// XdagSha256Digest currentTaskDigest = new XdagSha256Digest(); +// try { +// currentTaskDigest.sha256Update(data); +// byte[] state = currentTaskDigest.getState(); +// task[0] = new XdagField(MutableBytes.wrap(state)); +// currentTaskDigest.sha256Update(block.getXdagBlock().getField(14).getData()); +// } catch (IOException e) { +// log.error(e.getMessage(), e); +// } +// newTask.setTask(task); +// newTask.setTaskTime(XdagTime.getEpoch(sendTime)); +// newTask.setTaskIndex(taskIndex.get()); +// newTask.setDigest(currentTaskDigest); +// return newTask; +// } @Override public void run() { @@ -458,6 +405,7 @@ public void onMessage(io.xdag.listener.Message msg) { public static class Event { + @Getter private final Type type; private final Object data; private Object channel; @@ -477,10 +425,6 @@ public Event(Type type, Object data, Object channel) { this.channel = channel; } - public Type getType() { - return type; - } - @SuppressWarnings("unchecked") public T getData() { return (T) data; diff --git a/src/main/java/io/xdag/consensus/XdagSync.java b/src/main/java/io/xdag/consensus/XdagSync.java index 4707382e3..be12b1861 100644 --- a/src/main/java/io/xdag/consensus/XdagSync.java +++ b/src/main/java/io/xdag/consensus/XdagSync.java @@ -24,6 +24,9 @@ package io.xdag.consensus; +import static io.xdag.config.Constants.REQUEST_BLOCKS_MAX_TIME; +import static io.xdag.config.Constants.REQUEST_WAIT; + import com.google.common.util.concurrent.SettableFuture; import io.xdag.Kernel; import io.xdag.config.Config; @@ -34,7 +37,8 @@ import io.xdag.core.XdagState; import io.xdag.db.BlockStore; import io.xdag.net.Channel; -import io.xdag.net.manager.XdagChannelManager; +import io.xdag.net.ChannelManager; + import java.nio.ByteOrder; import java.util.LinkedList; import java.util.List; @@ -46,16 +50,16 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; + import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; + import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.MutableBytes; -import static io.xdag.config.Constants.*; - @Slf4j public class XdagSync { @@ -64,7 +68,7 @@ public class XdagSync { .daemon(true) .build(); - private final XdagChannelManager channelMgr; + private final ChannelManager channelMgr; private final BlockStore blockStore; private final ScheduledExecutorService sendTask; @Getter @@ -193,7 +197,7 @@ private void requestBlocks(long t, long dt) { * @param t request time */ private void sendGetBlocks(Channel xc, long t, SettableFuture sf) { - long randomSeq = xc.getXdag().sendGetBlocks(t, t + REQUEST_BLOCKS_MAX_TIME); + long randomSeq = xc.getP2pHandler().sendGetBlocks(t, t + REQUEST_BLOCKS_MAX_TIME); blocksRequestMap.put(randomSeq, sf); try { sf.get(REQUEST_WAIT, TimeUnit.SECONDS); @@ -213,7 +217,7 @@ private void findGetBlocks(Channel xc, long t, long dt, SettableFuture sf if (blockStore.loadSum(t, t + dt, lSums) <= 0) { return; } - long randomSeq = xc.getXdag().sendGetSums(t, t + dt); + long randomSeq = xc.getP2pHandler().sendGetSums(t, t + dt); sumsRequestMap.put(randomSeq, sf); try { Bytes sums = sf.get(REQUEST_WAIT, TimeUnit.SECONDS); diff --git a/src/main/java/io/xdag/core/BlockWrapper.java b/src/main/java/io/xdag/core/BlockWrapper.java index 1d28f8ad3..1ce5783e3 100644 --- a/src/main/java/io/xdag/core/BlockWrapper.java +++ b/src/main/java/io/xdag/core/BlockWrapper.java @@ -24,6 +24,7 @@ package io.xdag.core; +import io.xdag.net.Peer; import io.xdag.net.node.Node; import lombok.Getter; import lombok.Setter; @@ -37,16 +38,16 @@ public class BlockWrapper implements Cloneable { /** * 记录区块接收节点 */ - private Node remoteNode; + private Peer remotePeer; // NO_PARENT waiting time private long time; private boolean isOld; - public BlockWrapper(Block block, int ttl, Node remoteNode, boolean isOld) { + public BlockWrapper(Block block, int ttl, Peer remotePeer, boolean isOld) { this.block = block; this.ttl = ttl; - this.remoteNode = remoteNode; + this.remotePeer = remotePeer; this.isOld = isOld; } diff --git a/src/main/java/io/xdag/core/Blockchain.java b/src/main/java/io/xdag/core/Blockchain.java index 850ab751d..f017430bd 100644 --- a/src/main/java/io/xdag/core/Blockchain.java +++ b/src/main/java/io/xdag/core/Blockchain.java @@ -46,6 +46,8 @@ public interface Blockchain { void checkNewMain(); + long getLatestMainBlockNumber(); + List listMainBlocks(int count); List listMinedBlocks(int count); @@ -62,7 +64,6 @@ public interface Blockchain { List getBlocksByTime(long starttime, long endtime); - // TODO : 补充单元测试 // 启动检查主块链线程 void startCheckMain(long period); diff --git a/src/main/java/io/xdag/core/BlockchainImpl.java b/src/main/java/io/xdag/core/BlockchainImpl.java index b4cf6d1b8..8aa956f0c 100644 --- a/src/main/java/io/xdag/core/BlockchainImpl.java +++ b/src/main/java/io/xdag/core/BlockchainImpl.java @@ -39,7 +39,7 @@ import io.xdag.listener.BlockMessage; import io.xdag.listener.Listener; import io.xdag.listener.PretopMessage; -import io.xdag.mine.randomx.RandomX; +import io.xdag.crypto.RandomX; import io.xdag.utils.BasicUtils; import io.xdag.utils.BytesUtils; import io.xdag.utils.WalletUtils; @@ -105,7 +105,7 @@ public class BlockchainImpl implements Blockchain { private final XdagTopStatus xdagTopStatus; private final ScheduledExecutorService checkLoop; - private final RandomX randomXUtils; + private final RandomX randomx; private final List listeners = Lists.newArrayList(); private ScheduledFuture checkLoopFuture; private final long snapshotHeight; @@ -163,9 +163,9 @@ public BlockchainImpl(Kernel kernel) { } // add randomx utils - randomXUtils = kernel.getRandomx(); - if (randomXUtils != null) { - randomXUtils.setBlockchain(this); + randomx = kernel.getRandomx(); + if (randomx != null) { + randomx.setBlockchain(this); } checkLoop = new ScheduledThreadPoolExecutor(1, factory); @@ -423,7 +423,7 @@ public synchronized ImportResult tryToConnect(Block block) { blockStore.saveXdagStatus(xdagStats); // 如果区块输入不为0说明是交易块 - if (block.getInputs().size() != 0) { + if (!block.getInputs().isEmpty()) { if ((block.getInfo().getFlags() & BI_OURS) != 0) { log.info("XDAG:pool transaction(reward). block hash:{}", block.getHash().toHexString()); } @@ -626,6 +626,11 @@ public synchronized void checkNewMain() { } } + @Override + public long getLatestMainBlockNumber() { + return xdagStats.nmain; + } + /** * 回退到区块block * */ @@ -862,8 +867,8 @@ public void setMain(Block block) { // TODO:补充手续费 updateBlockRef(block, new Address(block)); - if (randomXUtils != null) { - randomXUtils.randomXSetForkTime(block); + if (randomx != null) { + randomx.randomXSetForkTime(block); } } @@ -888,8 +893,8 @@ public void unSetMain(Block block) { acceptAmount(block, XAmount.ZERO.subtract(amount)); acceptAmount(block, unApplyBlock(block)); - if (randomXUtils != null) { - randomXUtils.randomXUnsetForkTime(block); + if (randomx != null) { + randomx.randomXUnsetForkTime(block); } block.getInfo().setHeight(0); } @@ -966,7 +971,7 @@ public Block createMainBlock() { refs.addAll(orphans); } return new Block(kernel.getConfig(), sendTime[0], null, refs, true, null, - kernel.getConfig().getPoolSpec().getPoolTag(), -1); + kernel.getConfig().getNodeSpec().getNodeTag(), -1); } public Block createLinkBlock(String remark) { @@ -1063,7 +1068,7 @@ public BigInteger calculateCurrentBlockDiff(Block block) { } BigInteger blockDiff; // 初始区块自身难度设置 - if (randomXUtils != null && randomXUtils.isRandomxFork(XdagTime.getEpoch(block.getTimestamp())) + if (randomx != null && randomx.isRandomxFork(XdagTime.getEpoch(block.getTimestamp())) && XdagTime.isEndOfEpoch(block.getTimestamp())) { blockDiff = getDiffByRandomXHash(block); } else { @@ -1159,7 +1164,7 @@ public BigInteger getDiffByRandomXHash(Block block) { Bytes32 rxHash = Hash.sha256(block.getXdagBlock().getData().slice(0, 512 - 32)); data.set(0, rxHash); data.set(32, block.getXdagBlock().getField(15).getData()); - byte[] blockHash = randomXUtils.randomXBlockHash(data.toArray(), data.size(), epoch); + byte[] blockHash = randomx.randomXBlockHash(data.toArray(), data.size(), epoch); BigInteger diff; if (blockHash != null) { Bytes32 hash = Bytes32.wrap(Arrays.reverse(blockHash)); @@ -1507,7 +1512,7 @@ public void checkOrphan() { nblk = nblk / 61 + (b ? 1 : 0); } while (nblk-- > 0) { - Block linkBlock = createNewBlock(null, null, false, kernel.getConfig().getPoolSpec().getPoolTag()); + Block linkBlock = createNewBlock(null, null, false, kernel.getConfig().getNodeSpec().getNodeTag()); linkBlock.signOut(kernel.getWallet().getDefKey()); ImportResult result = this.tryToConnect(linkBlock); if (result == IMPORTED_NOT_BEST || result == IMPORTED_BEST) { diff --git a/src/main/java/io/xdag/mine/randomx/RandomX.java b/src/main/java/io/xdag/crypto/RandomX.java similarity index 99% rename from src/main/java/io/xdag/mine/randomx/RandomX.java rename to src/main/java/io/xdag/crypto/RandomX.java index eb2948559..417bbb0d0 100644 --- a/src/main/java/io/xdag/mine/randomx/RandomX.java +++ b/src/main/java/io/xdag/crypto/RandomX.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package io.xdag.mine.randomx; +package io.xdag.crypto; import com.sun.jna.Memory; import com.sun.jna.NativeLong; diff --git a/src/main/java/io/xdag/mine/randomx/RandomXMemory.java b/src/main/java/io/xdag/crypto/RandomXMemory.java similarity index 98% rename from src/main/java/io/xdag/mine/randomx/RandomXMemory.java rename to src/main/java/io/xdag/crypto/RandomXMemory.java index 1b8b88a73..476bfaf09 100644 --- a/src/main/java/io/xdag/mine/randomx/RandomXMemory.java +++ b/src/main/java/io/xdag/crypto/RandomXMemory.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package io.xdag.mine.randomx; +package io.xdag.crypto; import com.sun.jna.ptr.PointerByReference; import lombok.Getter; diff --git a/src/main/java/io/xdag/mine/MinerChannel.java b/src/main/java/io/xdag/mine/MinerChannel.java deleted file mode 100644 index e17dbf304..000000000 --- a/src/main/java/io/xdag/mine/MinerChannel.java +++ /dev/null @@ -1,414 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine; - -import static io.xdag.mine.miner.MinerStates.MINER_ACTIVE; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; -import io.netty.handler.timeout.IdleStateHandler; -import io.xdag.Kernel; -import io.xdag.config.Config; -import io.xdag.core.XAmount; -import io.xdag.core.XdagField; -import io.xdag.db.AddressStore; -import io.xdag.db.BlockStore; -import io.xdag.mine.handler.ConnectionLimitHandler; -import io.xdag.mine.handler.Miner03; -import io.xdag.mine.handler.MinerHandShakeHandler; -import io.xdag.mine.handler.MinerMessageHandler; -import io.xdag.mine.manager.MinerManager; -import io.xdag.mine.message.MinerMessageFactory; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerStates; -import io.xdag.net.XdagVersion; -import io.xdag.net.message.MessageFactory; -import io.xdag.utils.BytesUtils; - -import java.net.InetSocketAddress; -import java.nio.ByteOrder; -import java.util.Date; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicLong; - -import io.xdag.utils.WalletUtils; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes32; - -@Slf4j -@Getter -public class MinerChannel { - - /** - * 对应的是服务端的还是客户端的 - */ - private final boolean isServer; - private final Kernel kernel; - private final Config config; - private final BlockStore blockStore; - private final AddressStore addressStore; - private final MinerManager minerManager; - /** - * 存放的是连续16个任务本地计算的最大难度 每一轮放的都是最小hash 计算出来的diffs - */ - private final List maxDiffs = new CopyOnWriteArrayList<>(); - /** - * 记录的是出入站的消息 - */ - private final StatHandle inBound; - private final StatHandle outBound; - /** - * 这个channel是否是活跃的 仅当连接成功后变为true - */ - @Getter - @Setter - private boolean isActive; - /** - * 记录对应的矿工对象 - */ - @Getter - @Setter - private Miner miner; - /** - * 当前接受的最近的任务编号 - */ - @Getter - @Setter - private long taskIndex; - private long taskTime; - /** - * 每一轮任务分享share的次数 接收一次加1 - */ - @Getter - @Setter - private int sharesCounts; - /** - * 上一次发送shares 的时间 接收到shares 的时候会更新 - */ - @Getter - @Setter - private long lastSharesTime; - /** - * 连接成功的时间 暂时只适用于打印 没有其他用途 - */ - @Getter - private Date connectTime; - /** - * 如果是服务端端 则保存的是远程连接的客户端地址 若是客户端,则保存的是本地的地址 - */ - @Getter - @Setter - private InetSocketAddress inetAddress; - /** - * 发起连接的账户的地址块 - */ - @Getter - @Setter - private Bytes32 accountAddressHash; - @Getter - @Setter - private byte[] accountAddressHashByte; - /** - * 保存上一轮的share - */ - @Getter - @Setter - private byte[] share = new byte[32]; - /** - * 跟新为当前最小的hash 每收到一个share 后跟新 - */ - @Getter - @Setter - private byte[] lastMinHash = new byte[32]; - /** - * 记录prevDiff的次数 实际上类似于进行了多少次计算 - */ - @Getter - @Setter - private int prevDiffCounts; - @Setter - private ChannelHandlerContext ctx; - /** - * 记录的是当前任务所有难度之和,每当接收到一个新的nonce 会更新这个 - */ - @Getter - @Setter - private double prevDiff; - @Getter - @Setter - private double meanLogDiff; - @Getter - @Setter - private int boundedTaskCounter; - /** - * 保存这个channel 最后的计算的hash - */ - @Getter - @Setter - private Bytes32 minHash; - /** - * 各种处理器* - */ - private MinerHandShakeHandler minerHandShakeHandler; - private MinerMessageHandler minerMessageHandler; - private Miner03 miner03; - - - - /** - * 矿工名 - */ - @Getter - @Setter - private String workerName = StringUtils.EMPTY; - - /** - * 初始化 同时需要判断是服务器端还是客户端 - */ - public MinerChannel(Kernel kernel, boolean isServer) { - this.kernel = kernel; - this.config = kernel.getConfig(); - this.inBound = new StatHandle(); - this.outBound = new StatHandle(); - this.isServer = isServer; - - this.blockStore = kernel.getBlockStore(); - this.addressStore = kernel.getAddressStore(); - this.minerManager = kernel.getMinerManager(); - - // 容器的初始化 - for (int i = 0; i < 16; i++) { - maxDiffs.add(0.0); - } - } - - /** - * 初始化一个channel 并且注册到管道上 - * - * @param pipeline 注册的管道 - * @param inetSocketAddress 若是矿池开启的channel 则对应的是远程矿工地址,若为客户端开启,则为本地地址 - */ - public void init(ChannelPipeline pipeline, InetSocketAddress inetSocketAddress) { - this.inetAddress = inetSocketAddress; - - // 给管道添加各种消息处理器 - this.minerMessageHandler = new MinerMessageHandler(this); - this.miner03 = new Miner03(this, kernel); - - if (isServer) { - pipeline.addLast("connectionLimitHandler", new ConnectionLimitHandler(kernel.getConfig().getPoolSpec().getMaxConnectPerIp())); - } - - // 仅服务器端需要这个握手协议 接受 - this.minerHandShakeHandler = new MinerHandShakeHandler(this, kernel); - pipeline.addLast("LengthFieldBasedFrameDecoder",new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN,1024*1024,0,4,0,4,true)); - pipeline.addLast("MinerHandShake", minerHandShakeHandler); - } - - /** - * 根据版本创建一个信息工厂 - */ - private MessageFactory createMinerMessageFactory(XdagVersion version) { - return switch (version) { - case V03 -> new MinerMessageFactory(); - }; - } - - /** - * Active Channel and Add Handler 为管道添加各种处理器 - */ - public void activateHandler(ChannelHandlerContext ctx, XdagVersion version) { - log.debug("Activate Handler"); - MessageFactory messageFactory = createMinerMessageFactory(version); - minerMessageHandler.setMessageFactory(messageFactory); - ctx.pipeline().addLast("MinerMessageHandler", minerMessageHandler); - ctx.pipeline().addLast(new IdleStateHandler(64, 0, 0)); - ctx.pipeline().addLast("Miner03Handler", miner03); - } - - public boolean initMiner(Bytes32 accountAddressHash) { - this.accountAddressHash = accountAddressHash; - this.accountAddressHashByte = BytesUtils.byte32ToArray(accountAddressHash.mutableCopy()); - String addrHexStr = WalletUtils.toBase58(accountAddressHashByte); - log.debug("Init A Miner:" + addrHexStr); - // 判断这个矿工是否已经存在了 - if (minerManager !=null && minerManager.getActivateMiners().containsKey(accountAddressHash)) { - log.debug("Miner:{} already exists", addrHexStr); - this.miner = minerManager.getActivateMiners().get(accountAddressHash); - if (miner !=null && miner.getConnChannelCounts() < config.getPoolSpec().getMaxMinerPerAccount()) { - this.miner = minerManager.getActivateMiners().get(accountAddressHash); - this.miner.putChannel(this.inetAddress, this); - this.miner.setMinerStates(MINER_ACTIVE); - return true; - } else { - log.debug("Too many connections to the same miner:{}", addrHexStr); - return false; - } - } else { - this.miner = new Miner(accountAddressHash); - Objects.requireNonNull(minerManager).getActivateMiners().put(accountAddressHash, miner); - this.miner.putChannel(this.inetAddress, this); - this.miner.setMinerStates(MINER_ACTIVE); - return true; - } - } - - public void onDisconnect() { - miner03.dropConnection(); - } - - public StatHandle getInBound() { - return inBound; - } - - public StatHandle getOutBound() { - return outBound; - } - - public boolean isServer() { - return isServer; - } - - public void setIsActivate(boolean bool) { - isActive = bool; - } - - public void setConnectTime(Date time) { - connectTime = time; - } - - public void addShareCounts(int i) { - sharesCounts += i; - } - - /** - * 矿池发送给矿工的任务 - */ - public void sendTaskToMiner(XdagField[] fields) { - miner03.sendMessage(Bytes.wrap(fields[0].getData(), fields[1].getData())); - } - - /** - * 矿池发送余额给矿工 - */ - public void sendBalance() { - XAmount amount = XAmount.ZERO; - if (!addressStore.addressIsExist(accountAddressHashByte)){ - log.debug("Can't found address,{}", WalletUtils.toBase58(accountAddressHashByte)); - } else { - amount = addressStore.getBalanceByAddress(accountAddressHashByte); - } - MutableBytes32 data = MutableBytes32.create(); - data.set(0, amount.toXAmount().toBytes()); - data.set(8, Bytes.wrap(accountAddressHashByte)); - log.debug("update miner balance {}", data.toHexString()); - miner03.sendMessage(data); - } - - public long getTaskTime() { - return taskTime; - } - - public void setTaskTime(long taskTime) { - this.taskTime = taskTime; - } - - public void addPrevDiff(double i) { - prevDiff += i; - } - - public void addPrevDiffCounts() { - this.prevDiffCounts++; - } - - public void addMaxDiffs(int index, double diff) { - maxDiffs.set(index, diff); - } - - public double getMaxDiffs(int index) { - return maxDiffs.get(index); - } - - public void addBoundedTaskCounter() { - this.boundedTaskCounter++; - } - - @Override - public String toString() { - return ""; - } - - public void dropConnection() { - miner03.dropConnection(); - } - - public void updateMiner(Miner miner) { - this.miner = miner; - this.accountAddressHash = miner.getAddressHash(); - miner.putChannel(this.getInetAddress(), this); - miner.setMinerStates(MinerStates.MINER_ACTIVE); - } - - public String getAddressHash(){ - if(this.miner == null){ - return StringUtils.EMPTY; - }else { - return WalletUtils.toBase58(accountAddressHashByte); - } - } - - /** - * 内部类 用于计算这个channel 的入栈和出战信息 - */ - public static class StatHandle { - - AtomicLong count = new AtomicLong(0); - - public void add() { - count.getAndIncrement(); - } - - public void add(long delta) { - count.addAndGet(delta); - } - - public long get() { - return count.get(); - } - - @Override - public String toString() { - return count.toString(); - } - } -} diff --git a/src/main/java/io/xdag/mine/MinerChannelInitializer.java b/src/main/java/io/xdag/mine/MinerChannelInitializer.java deleted file mode 100644 index 144b410d6..000000000 --- a/src/main/java/io/xdag/mine/MinerChannelInitializer.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelOption; -import io.netty.channel.FixedRecvByteBufAllocator; -import io.xdag.Kernel; -import java.net.InetSocketAddress; -import java.util.concurrent.atomic.AtomicInteger; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class MinerChannelInitializer extends ChannelInitializer { - - private final Kernel kernel; - private final boolean isServer; - - public MinerChannelInitializer(Kernel kernel, boolean isServer) { - this.kernel = kernel; - this.isServer = isServer; - } - - @Override - protected void initChannel(Channel ch) { - AtomicInteger channelsAccount = kernel.getChannelsAccount(); - int channelLimit = kernel.getConfig().getPoolSpec().getGlobalMinerChannelLimit(); - if (channelsAccount.get() >= channelLimit) { - ch.close(); - log.warn("Pool Miner Channel Limit {}, Too Many Channels In This Pool.", channelLimit); - return; - } - InetSocketAddress channelAddress = isServer - ? (InetSocketAddress)ch.remoteAddress() - : new InetSocketAddress( - kernel.getConfig().getPoolSpec().getPoolIp(), kernel.getConfig().getPoolSpec().getPoolPort()); - MinerChannel minerChannel = new MinerChannel(kernel, isServer); - minerChannel.init(ch.pipeline(), channelAddress); - ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(256 * 1024)); - ch.config().setOption(ChannelOption.TCP_NODELAY, true); - ch.config().setOption(ChannelOption.SO_RCVBUF, 256 * 1024); - ch.config().setOption(ChannelOption.SO_BACKLOG, 1024); - } -} diff --git a/src/main/java/io/xdag/mine/MinerServer.java b/src/main/java/io/xdag/mine/MinerServer.java deleted file mode 100644 index 8ea3aee40..000000000 --- a/src/main/java/io/xdag/mine/MinerServer.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine; - -import io.netty.bootstrap.ServerBootstrap; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelOption; -import io.netty.channel.DefaultMessageSizeEstimator; -import io.netty.channel.EventLoopGroup; -import io.netty.channel.epoll.EpollEventLoopGroup; -import io.netty.channel.kqueue.KQueueEventLoopGroup; -import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.handler.logging.LoggingHandler; -import io.netty.util.NettyRuntime; -import io.xdag.Kernel; -import io.xdag.utils.NettyUtils; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.SystemUtils; - -@Slf4j -public class MinerServer { - private Kernel kernel; - private EventLoopGroup bossGroup; - private EventLoopGroup workerGroup; - private ChannelFuture channelFuture; - private final int workerThreadPoolSize = NettyRuntime.availableProcessors() * 4; - - public MinerServer(Kernel kernel) { - this.kernel = kernel; - } - - public void start() { - start(kernel.getConfig().getPoolSpec().getPoolIp(), kernel.getConfig().getPoolSpec().getPoolPort()); - } - - public void start(String ip, int port) { - try { - if(SystemUtils.IS_OS_LINUX) { - bossGroup = new EpollEventLoopGroup(); - workerGroup = new EpollEventLoopGroup(workerThreadPoolSize); - } else if(SystemUtils.IS_OS_MAC) { - bossGroup = new KQueueEventLoopGroup(); - workerGroup = new KQueueEventLoopGroup(workerThreadPoolSize); - - } else { - bossGroup = new NioEventLoopGroup(); - workerGroup = new NioEventLoopGroup(workerThreadPoolSize); - } - - ServerBootstrap b = NettyUtils.nativeEventLoopGroup(bossGroup, workerGroup); - b.childOption(ChannelOption.TCP_NODELAY, true); - b.childOption(ChannelOption.SO_KEEPALIVE, true); - b.childOption(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); - b.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, kernel.getConfig().getPoolSpec().getConnectionTimeout()); - b.handler(new LoggingHandler()); - b.childHandler(new MinerChannelInitializer(kernel, true)); - channelFuture = b.bind(ip, port).sync(); - log.info("Xdag Pool start host:[{}:{}]", ip, port); - } catch (Exception e) { - log.error("Xdag Pool start error:{}.", e.getMessage(), e); - } - } - - public void close() { - if (channelFuture != null && channelFuture.channel().isOpen()) { - try { - channelFuture.channel().close().sync(); - workerGroup.shutdownGracefully(); - bossGroup.shutdownGracefully(); - log.info("Xdag Pool closed."); - } catch (Exception e) { - log.error("Xdag Pool close error:{}", e.getMessage(), e); - } - } - } -} diff --git a/src/main/java/io/xdag/mine/handler/Miner03.java b/src/main/java/io/xdag/mine/handler/Miner03.java deleted file mode 100644 index d3490c03e..000000000 --- a/src/main/java/io/xdag/mine/handler/Miner03.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.handler; - -import static io.xdag.utils.BytesUtils.compareTo; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.handler.timeout.IdleState; -import io.netty.handler.timeout.IdleStateEvent; -import io.xdag.Kernel; -import io.xdag.consensus.SyncManager; -import io.xdag.core.Block; -import io.xdag.core.BlockWrapper; -import io.xdag.core.ImportResult; -import io.xdag.db.AddressStore; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.manager.MinerManager; -import io.xdag.mine.message.NewBalanceMessage; -import io.xdag.mine.message.NewTaskMessage; -import io.xdag.mine.message.TaskShareMessage; -import io.xdag.mine.message.WorkerNameMessage; -import io.xdag.mine.miner.Miner; -import io.xdag.net.message.Message; -import io.xdag.net.message.impl.NewBlockMessage; -import io.xdag.utils.BasicUtils; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -import io.xdag.utils.WalletUtils; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.units.bigints.UInt64; - -@Slf4j -public class Miner03 extends SimpleChannelInboundHandler { - - private final Kernel kernel; - private final MinerChannel channel; - private final AddressStore addressStore; - private final MinerManager minerManager; - private final SyncManager syncManager; - private ChannelHandlerContext ctx; - - private int readIdleTimes; - private int writeIdleTimes; - private int allIdleTimes; - - public Miner03(MinerChannel channel, Kernel kernel) { - this.channel = channel; - this.kernel = kernel; - addressStore = kernel.getAddressStore(); - minerManager = kernel.getMinerManager(); - syncManager = kernel.getSyncMgr(); - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Message msg) { - switch (msg.getCommand()) { - case NEW_BALANCE -> processNewBalance((NewBalanceMessage) msg); - case TASK_SHARE -> processTaskShare((TaskShareMessage) msg); - case NEW_TASK -> processNewTask((NewTaskMessage) msg); - case NEW_BLOCK -> processNewBlock((NewBlockMessage) msg); - case WORKER_NAME ->processWorkerName((WorkerNameMessage) msg); - default -> log.warn("There is no message type for this corresponding data, the content HEX is {}", msg.getEncoded().toHexString()); - } - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) { - channel.setCtx(ctx); - this.ctx = ctx; - log.debug("ip&port:{},Address:{} add handler",channel.getInetAddress().toString(),channel.getAddressHash()); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - log.error(cause.getMessage(), cause); - if (cause instanceof IOException) { - ctx.channel().closeFuture(); - log.debug("ExceptionCaught:{}, Close miner channel:{}, address:{}, workName:{}", - cause.getMessage(), channel.getInetAddress().toString(), channel.getAddressHash(), channel.getWorkerName()); - } - channel.setActive(false); - } - - @Override - public void handlerRemoved(ChannelHandlerContext ctx) { - log.debug("Close miner channel:{}, address:{}, workName:{}", - channel.getInetAddress().toString(), channel.getAddressHash(), channel.getWorkerName()); - ctx.channel().closeFuture(); - channel.onDisconnect(); - } - - /** - * ********************** Message Processing * *********************** - */ - protected void processNewBlock(NewBlockMessage msg) { - Block block = msg.getBlock(); - ImportResult importResult = syncManager - .validateAndAddNewBlock(new BlockWrapper(block, kernel.getConfig().getNodeSpec().getTTL())); - if (importResult.isNormal()) { - log.debug("XDAG:receive transaction. A transaction from ip&port:{},wallet/miner: {}, block hash: {}", - channel.getInetAddress().toString(),channel.getAddressHash(),block.getHash().toHexString()); - } - } - - protected void processNewBalance(NewBalanceMessage msg) { - // TODO: 2020/5/9 Process the balance information received by the miner Miner function - log.debug("ip&port:{},Address:{} receive new balance: [{}]", - channel.getInetAddress().toString(), WalletUtils.toBase58(channel.getAccountAddressHashByte()),BasicUtils.amount2xdag(UInt64.fromBytes(msg.getEncoded().slice(0,8)))); - } - - protected void processNewTask(NewTaskMessage msg) { - // TODO: 2020/5/9 Handle new tasks received by miners Miner functions - log.debug("Address:{} receive new task: [{}]", - WalletUtils.toBase58(channel.getAccountAddressHashByte()),BasicUtils.amount2xdag(UInt64.fromBytes(msg.getEncoded().slice(0,8)))); - } - - protected void processTaskShare(TaskShareMessage msg) { - //share地址不一致,修改对应的miner地址 否则向下进行处理 - //msg 最后12-32位反转 与 addressHashByte相等 - //实际是当初有伪块时区别矿机和钱包用的 - if (compareTo(msg.getEncoded().reverse().toArray(), 0, 20, channel.getAccountAddressHashByte(),0,20) != 0) { - //TODO: 确定矿机协议,不再获取区块,直接获取Base58或者公钥的hash - - Miner miner = kernel.getMinerManager().getActivateMiners() - .get(channel.getAccountAddressHash()); - if (miner == null) { - miner = new Miner(channel.getAccountAddressHash()); - log.debug("Create new miner channel:{}, address:{}, workerName:{}.", - channel.getInetAddress().toString(), WalletUtils.toBase58(miner.getAddressHashByte()), channel.getWorkerName()); - minerManager.addActiveMiner(miner); - } - // Change the address corresponding to the channel and replace the new miner connection - channel.updateMiner(miner); - log.debug("RandomX miner channel:{}, address:{}, workerName:{}", - channel.getInetAddress().toString(), WalletUtils.toBase58(miner.getAddressHashByte()), channel.getWorkerName()); - } - - if (channel.getSharesCounts() <= kernel.getConfig().getPoolSpec().getMaxShareCountPerChannel()) { - channel.addShareCounts(1); - minerManager.onNewShare(channel, msg); - } else { - log.debug("Too many Shares from address:{},ip&port:{},Reject...", - channel.getAddressHash(),channel.getInetAddress().toString()); - channel.onDisconnect(); - } - - } - - private void processWorkerName(WorkerNameMessage msg) { - byte[] workerNameByte = msg.getEncoded().reverse().slice(4).toArray(); - String workerName = new String(workerNameByte, StandardCharsets.UTF_8).trim(); - log.debug("Pool receive miner address:{},workerName:{},ip&port:{}", - channel.getAddressHash() ,workerName,channel.getInetAddress().toString()); - channel.setWorkerName(workerName); - } - - /** - * Send Task Message - */ - public void sendMessage(Bytes bytes) { - ctx.channel().writeAndFlush(bytes.toArray()); - } - - public void dropConnection() { - disconnect(); - } - - public void disconnect() { - if(ctx != null ) { - ctx.close(); - } - - if(channel != null) { - channel.setActive(false); - } - - if(channel != null) { - log.info("Disconnect channel: {} with address: {}", - channel.getInetAddress().toString(), channel.getAddressHash()); - } - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { - try { - if (evt instanceof IdleStateEvent e) { - if (e.state() == IdleState.READER_IDLE) { - readIdleTimes++; - } else if (e.state() == IdleState.WRITER_IDLE) { - writeIdleTimes++; - } else if (e.state() == IdleState.ALL_IDLE) { - allIdleTimes++; - } - log.debug("socket:{}, xdag address:{}, timeout with:{}", channel.getInetAddress().toString(), channel.getAddressHash(),((IdleStateEvent)evt).state().toString()); - } - - if (readIdleTimes > 3) { - log.warn("close channel, socket:{}, xdag address:{}.", channel.getInetAddress().toString(), channel.getAddressHash()); - channel.onDisconnect(); - } - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } - -} diff --git a/src/main/java/io/xdag/mine/handler/MinerHandShakeHandler.java b/src/main/java/io/xdag/mine/handler/MinerHandShakeHandler.java deleted file mode 100644 index 7053fccda..000000000 --- a/src/main/java/io/xdag/mine/handler/MinerHandShakeHandler.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.handler; - -import static io.xdag.net.XdagVersion.V03; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.timeout.IdleState; -import io.netty.handler.timeout.IdleStateEvent; -import io.xdag.Kernel; -import io.xdag.crypto.Base58; -import io.xdag.db.AddressStore; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.manager.MinerManager; -import io.xdag.utils.BytesUtils; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -import io.xdag.utils.WalletUtils; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes32; - -@Slf4j -public class MinerHandShakeHandler extends ByteToMessageDecoder { - - private final MinerChannel channel; - private final Kernel kernel; - private final MinerManager minerManager; - private final AddressStore addressStore; - public static final int MESSAGE_SIZE = 24; - - public MinerHandShakeHandler(MinerChannel channel, Kernel kernel) { - this.channel = channel; - this.kernel = kernel; - minerManager = kernel.getMinerManager(); - addressStore = kernel.getAddressStore(); - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { - if (in.readableBytes() >= MESSAGE_SIZE) { - log.debug("Receive a address from ip&port:{}",ctx.channel().remoteAddress()); - byte[] message = new byte[MESSAGE_SIZE]; - in.readBytes(message); - if(!Base58.checkBytes24(message)){ - log.warn("Address hash is invalid"); - ctx.close(); - return; - } - - byte[] addressHash = Arrays.copyOfRange(message,0,20); - checkProtocol(ctx,addressHash); - if (!initMiner(BytesUtils.arrayToByte32(addressHash))) { - log.debug("too many connect for the miner: {},ip&port:{}", - WalletUtils.toBase58(channel.getAccountAddressHashByte()),channel.getInetAddress().toString()); - ctx.close(); - return; - } - AtomicInteger channelsAccount = kernel.getChannelsAccount(); - if (channelsAccount.get() >= kernel.getConfig().getPoolSpec().getGlobalMinerChannelLimit()) { - ctx.close(); - log.warn("Too many channels in this pool"); - return; - } - - kernel.getChannelsAccount().getAndIncrement(); - channel.getInBound().add(1L); - minerManager.addActivateChannel(channel); - channel.setIsActivate(true); - channel.setConnectTime(new Date(System.currentTimeMillis())); - channel.setAccountAddressHash(BytesUtils.arrayToByte32(addressHash)); - channel.setAccountAddressHashByte(addressHash); - channel.activateHandler(ctx, V03); - ctx.pipeline().remove(this); - // TODO: 2020/5/8 There may be a bug here. If you join infinitely, won't it be created wirelessly? - log.debug("add a new miner from ip&port:{},miner's address: [" + WalletUtils.toBase58(channel.getAccountAddressHashByte()) + "]",channel.getInetAddress()); - } else { - log.debug("length less than " + MESSAGE_SIZE + " bytes"); - } - } - - public void checkProtocol(ChannelHandlerContext ctx, byte[] address) { - boolean importResult = addressStore.addressIsExist(address); - if (!importResult) { - addressStore.addAddress(address); - log.info("XDAG:new miner connect. New address: {} with channel: {} connect.", - WalletUtils.toBase58(address), channel.getInetAddress()); - } else { - log.info("XDAG:old miner connect. Address: {} with channel {} connect.", - WalletUtils.toBase58(address), channel.getInetAddress()); - } - } - - public boolean initMiner(Bytes32 hash) { - return channel.initMiner(hash); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - if (cause instanceof IOException) { - log.debug("The miner of the remote host is: {} closed ip&port:{} connection.", - channel.getAddressHash(),channel.getInetAddress().toString()); - ctx.channel().closeFuture(); - } else { - log.error(cause.getMessage(), cause); - } - channel.onDisconnect(); - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { - try { - Channel nettyChannel = ctx.channel(); - if (evt instanceof IdleStateEvent e) { - if (e.state() == IdleState.READER_IDLE) { - nettyChannel.closeFuture(); - if (log.isDebugEnabled()) { - log.debug(nettyChannel.remoteAddress() - + "---No data was received for a while ,read time out... ..."); - } - } else if (e.state() == IdleState.WRITER_IDLE) { - nettyChannel.closeFuture(); - if (log.isDebugEnabled()) { - log.debug( - nettyChannel.remoteAddress() + "---No data was sent for a while.write time out... ..."); - } - } - } - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } -} diff --git a/src/main/java/io/xdag/mine/handler/MinerMessageHandler.java b/src/main/java/io/xdag/mine/handler/MinerMessageHandler.java deleted file mode 100644 index e9deaadb4..000000000 --- a/src/main/java/io/xdag/mine/handler/MinerMessageHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.handler; - -import static io.xdag.net.message.XdagMessageCodes.NEW_BALANCE; -import static io.xdag.net.message.XdagMessageCodes.TASK_SHARE; -import static io.xdag.net.message.XdagMessageCodes.WORKER_NAME; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageCodec; -import io.xdag.mine.MinerChannel; -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageFactory; -import io.xdag.utils.BytesUtils; -import io.xdag.utils.WalletUtils; -import jakarta.xml.bind.DatatypeConverter; -import java.io.IOException; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Hex; -import org.apache.tuweni.bytes.MutableBytes; - -@Slf4j -public class MinerMessageHandler extends ByteToMessageCodec { - - private final MinerChannel channel; - private final int DATA_SIZE = 32;// length of each field - private static final String WORKERNAME_HEADER_WORD = "f46b9853"; - private MessageFactory messageFactory; - - public MinerMessageHandler(MinerChannel channel) { - this.channel = channel; - } - - public void setMessageFactory(MessageFactory messageFactory) { - this.messageFactory = messageFactory; - } - - @Override - protected void encode(ChannelHandlerContext ctx, byte[] bytes, ByteBuf out) { - int len = bytes.length; - long sectorNo = channel.getOutBound().get(); - if (len == DATA_SIZE) { - log.debug("Send a message for miner: {} ip&port:{} with sectorNo={},length={}", - WalletUtils.toBase58(channel.getAccountAddressHashByte()),channel.getInetAddress().toString(),sectorNo, len); - BytesUtils.arrayReverse(bytes); - out.writeBytes(bytes); - channel.getOutBound().add(); - } else if (len == 2 * DATA_SIZE) { - log.debug("Send a message for miner:{} ip&port:{} with sectorNo={},length={}, hex is[{}]", - channel.getAddressHash(),channel.getInetAddress().toString(),sectorNo, len, Hex.encodeHexString(bytes)); - out.writeBytes(bytes); - channel.getOutBound().add(2); - } else { - log.debug("Send a error message of this length:{} field type to miner:{} ip&port:{}.", - len,channel.getAddressHash(),channel.getInetAddress().toString()); - } - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { - Message msg; - int len = in.readableBytes(); - // The length of the received message is 32 bytes - if (len == DATA_SIZE) { - log.debug("Received a message from the miner:{} ip&port:{},msg len == 32", - WalletUtils.toBase58(channel.getAccountAddressHashByte()), - channel.getInetAddress().toString()); - byte[] data = new byte[DATA_SIZE]; - in.readBytes(data); - BytesUtils.arrayReverse(data); - //The message received is the worker_name - if(BytesUtils.compareTo(data,28,4, DatatypeConverter.parseHexBinary(WORKERNAME_HEADER_WORD),0,4)==0){ - msg = messageFactory.create(WORKER_NAME.asByte(),MutableBytes.wrap(data)); - }else { - if (channel.isServer()) { - // If it is the server, the one-byte message received can only be task-share - msg = messageFactory.create(TASK_SHARE.asByte(), MutableBytes.wrap(data)); - } else { - msg = messageFactory.create(NEW_BALANCE.asByte(), MutableBytes.wrap(data)); - } - } - channel.getInBound().add(); - // When a message of 512 bytes is received, it means that a transaction is sent from a miner after receiving a block. - } else { - log.error("There is no type information from the message with length:{} from Address:{} ip&port:{}", - len,channel.getAddressHash(),channel.getInetAddress().toString()); - return; - } - - if (msg != null) { - out.add(msg); - } - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - if (cause instanceof IOException) { - log.debug("The remote host closed a connection,whose address is : {} ", - channel.getAddressHash()); - } else { - log.error(cause.getMessage(), cause); - } - channel.onDisconnect(); - - } -} diff --git a/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java b/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java deleted file mode 100644 index fdcb185e6..000000000 --- a/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java +++ /dev/null @@ -1,670 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.manager; - -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_IN; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_OUTPUT; -import static io.xdag.utils.BasicUtils.compareAmountTo; -import static io.xdag.utils.BasicUtils.pubAddress2Hash; -import static io.xdag.utils.BytesUtils.compareTo; -import static java.lang.Math.E; - -import io.xdag.Kernel; -import io.xdag.Wallet; -import io.xdag.config.Config; -import io.xdag.config.PoolConfig; -import io.xdag.consensus.Task; -import io.xdag.core.Address; -import io.xdag.core.Block; -import io.xdag.core.BlockWrapper; -import io.xdag.core.Blockchain; -import io.xdag.core.XAmount; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerStates; -import io.xdag.utils.BigDecimalUtils; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; - -import io.xdag.utils.WalletUtils; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes32; -import org.hyperledger.besu.crypto.KeyPair; - -import com.google.common.collect.Lists; - -@Slf4j -public class AwardManagerImpl implements AwardManager, Runnable { - - /** - * 每一轮的确认数是16 - */ - private static final int CONFIRMATIONS_COUNT = 16; - /** - * 矿池自己的收益 - */ - private static double poolRation; - /** - * 出块矿工占比 - */ - private static double minerRewardRation; - /** - * 基金会的奖励 - */ - private static double fundRation; - /** - * 矿工的参与奖励 - */ - private static double directRation; - private final double DBL = 2.2204460492503131E-016; - private final Kernel kernel; - private final Blockchain blockchain; - private final Wallet wallet; - private final BlockingQueue awardBlockBlockingQueue = new LinkedBlockingQueue<>(); - // 定义每一个部分的收益占比 - protected Miner poolMiner; - /** - * 存放的是过去十六个区块的hash - */ - protected List blockHashs = new CopyOnWriteArrayList<>(); - protected List minShares = new CopyOnWriteArrayList<>(new ArrayList<>(16)); - protected volatile long currentTaskTime; - protected volatile long currentTaskIndex; - protected Config config; - private List miners; - @Setter - private MinerManager minerManager; - private ArrayList diff = Lists.newArrayList(); - private ArrayList prev_diff = Lists.newArrayList(); - private final String fundAddress; - private final ExecutorService workExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() - .namingPattern("AwardManager-work-thread") - .daemon(true) - .build()); - - private volatile boolean isRunning = false; - - public AwardManagerImpl(Kernel kernel) { - this.kernel = kernel; - this.config = kernel.getConfig(); - this.blockchain = kernel.getBlockchain(); - this.wallet = kernel.getWallet(); - this.poolMiner = kernel.getPoolMiner(); - this.minerManager = kernel.getMinerManager(); - init(); - setPoolConfig(); - this.fundAddress = config.getPoolSpec().getFundAddress(); - } - - /** - * 计算一个矿工所有未支付的数据 返回的是一个平均的 diff 对过去的十六个难度的平均值 - */ - private static double processOutdatedMiner(Miner miner) { - log.debug("processOutdatedMiner"); - double sum = 0.0; - int diffcount = 0; - double temp; - for (int i = 0; i < CONFIRMATIONS_COUNT; i++) { - if ((temp = miner.getMaxDiffs(i)) > 0) { - sum += temp; - miner.setMaxDiffs(i, 0.0); - ++diffcount; - } - } - - if (diffcount > 0) { - sum /= diffcount; - } - return sum; - } - - /** - * 实现一个由难度转换为pay 的函数 - */ - private static double diffToPay(double sum, int diffCount) { - double result = 0.0; - if (diffCount > 0) { - result = Math.pow(E, ((sum / diffCount) - 20)) * diffCount; - } - return result; - } - - @Override - public void run() { - while (isRunning) { - try { - AwardBlock awardBlock = awardBlockBlockingQueue.poll(1, TimeUnit.SECONDS); - if(awardBlock != null) { - log.debug("award block:{}", awardBlock.hash.toHexString()); - payAndaddNewAwardBlock(awardBlock); - } - } catch (InterruptedException e) { - log.error(" can not take the awardBlock from awardBlockQueue" + e.getMessage(), e); - } - } - } - - @Override - public void start() { - isRunning = true; - workExecutor.execute(this); - log.debug("AwardManager started."); - } - - @Override - public void stop() { - isRunning = false; - workExecutor.shutdown(); - } - - @Override - public void addAwardBlock(Bytes32 share, Bytes32 hash, long generateTime) { - AwardBlock awardBlock = new AwardBlock(); - awardBlock.share = share; - awardBlock.hash = hash; - awardBlock.generateTime = generateTime; - if (!awardBlockBlockingQueue.offer(awardBlock)) { - log.error("Failed to add a awardBlock to the b queue!"); - } - } - - public void init() { - log.debug("AwardManager init."); - // 容器的初始化 - for (int i = 0; i < 16; i++) { - blockHashs.add(null); - minShares.add(null); - } - } - - public void updatePoolConfig(double poolFeeRation,double poolRewardRation,double poolDirectRation, double poolFundRation) { - poolRation = BigDecimalUtils.div(poolFeeRation, 100); - if (poolRation < 0) { - poolRation = 0; - } else if (poolRation > 1) { - poolRation = 1; - } - - minerRewardRation = BigDecimalUtils.div(poolRewardRation, 100); - if (minerRewardRation < 0) { - minerRewardRation = 0; - } else if (poolRation + minerRewardRation > 1) { - minerRewardRation = 1 - poolRation; - } - - directRation = BigDecimalUtils.div(poolDirectRation, 100); - if (directRation < 0) { - directRation = 0; - } else if (poolRation + minerRewardRation + directRation > 1) { - directRation = 1 - poolRation - minerRewardRation; - } - - fundRation = BigDecimalUtils.div(poolFundRation, 100); - if (fundRation < 0) { - fundRation = 0; - } else if (poolRation + minerRewardRation + directRation + fundRation > 1) { - fundRation = 1 - poolRation - minerRewardRation - directRation; - } - } - - @Override - public PoolConfig getPoolConfig() { - PoolConfig.PoolConfigBuilder configBuilder = PoolConfig.builder(); - configBuilder.poolRation(poolRation); - configBuilder.fundRation(fundRation); - configBuilder.directRation(directRation); - configBuilder.minerRewardRation(minerRewardRation); - return configBuilder.build(); - } - - /** - * 给矿池设置一些支付上的参数 - */ - private void setPoolConfig() { - poolRation = BigDecimalUtils.div(config.getPoolSpec().getPoolRation(), 100); - if (poolRation < 0) { - poolRation = 0; - } else if (poolRation > 1) { - poolRation = 1; - } - - minerRewardRation = BigDecimalUtils.div(config.getPoolSpec().getRewardRation(), 100); - if (minerRewardRation < 0) { - minerRewardRation = 0; - } else if (poolRation + minerRewardRation > 1) { - minerRewardRation = 1 - poolRation; - } - - directRation = BigDecimalUtils.div(config.getPoolSpec().getDirectRation(), 100); - if (directRation < 0) { - directRation = 0; - } else if (poolRation + minerRewardRation + directRation > 1) { - directRation = 1 - poolRation - minerRewardRation; - } - - fundRation = BigDecimalUtils.div(config.getPoolSpec().getFundRation(), 100); - if (fundRation < 0) { - fundRation = 0; - } else if (poolRation + minerRewardRation + directRation + fundRation > 1) { - fundRation = 1 - poolRation - minerRewardRation - directRation; - } - } - - /** - * 对主块进行支付 并且设置当前这一轮主块的相关信息 - */ - public void payAndaddNewAwardBlock(AwardBlock awardBlock) { - log.debug("Pay miner"); - payMiners(awardBlock.generateTime); - log.debug("set index:" + (int) ((awardBlock.generateTime >> 16) & config.getPoolSpec().getAwardEpoch())); - blockHashs.set((int) ((awardBlock.generateTime >> 16) & config.getPoolSpec().getAwardEpoch()), awardBlock.hash); - minShares.set((int) ((awardBlock.generateTime >> 16) & config.getPoolSpec().getAwardEpoch()), awardBlock.share); - } - - @Override - public void onNewTask(Task task) { - currentTaskTime = task.getTaskTime(); - currentTaskIndex = task.getTaskIndex(); - } - - /** - * @param time 时间段 - * @return 错误代码 -1 没有矿工参与挖矿 不进行支付操作 -2 找不到对应的区块hash 或者 结果nonce -3 找不到对应的区块 - * -4区块余额不足,不是主块不进行支付 -5 余额分配失败 -6 找不到签名密钥 -7 难度太小 不予支付 - */ - public int payMiners(long time) { - log.debug("=========== start payMiners for time [{}]===========", time); - // 获取到的是当前任务的对应的+1的位置 以此延迟16轮 - int index = (int) (((time >> 16) + 1) & config.getPoolSpec().getAwardEpoch()); - int keyPos = -1; - int minerCounts = 0; - PayData payData = new PayData(); - - // 每一个区块最多可以放多少交易 这个要由密钥的位置来决定 - int payminersPerBlock; - miners = Lists.newArrayList(); - // 统计矿工的数量 - if (minerManager != null) { - for (Miner miner : minerManager.getActivateMiners().values()) { - //Filter fake blocks - miners.add(miner); - minerCounts++; - log.debug("The number of miners is[{}]", minerCounts); - } - } - - // 没有矿工挖矿,直接全部收入交由地址块 - if (minerCounts <= 0) { - log.debug("no miners"); - return -1; - } - - // 获取到要计算的hash 和对应的nocne - Bytes32 hash = blockHashs.get(index) == null ? null : blockHashs.get(index); - Bytes32 nonce = minShares.get(index) == null ? null : minShares.get(index); - - if (hash == null || nonce == null) { - log.debug("can not find the hash or nonce ,hash is null?[{}],nonce is null ?[{}]", hash == null, - nonce == null); - return -2; - } - - // 获取到这个区块 查询时要把前面的置0 - MutableBytes32 hashlow = MutableBytes32.create(); -// Bytes32.wrap(BytesUtils.fixBytes(hash, 8, 24)); - hashlow.set(8, Bytes.wrap(hash).slice(8, 24)); - Block block = blockchain.getBlockByHash(hashlow, true); - //TODO - log.debug("Hash low [{}]",hashlow.toHexString()); - if (keyPos < 0) { - if (kernel.getBlockchain().getMemOurBlocks().get(hashlow) == null) { - keyPos = kernel.getBlockStore().getKeyIndexByHash(hashlow); - } else { - keyPos = kernel.getBlockchain().getMemOurBlocks().get(hashlow); - } - log.debug("keypos : " + keyPos); - if (keyPos < 0) { - return -2; - } - } - - if (block == null) { - log.debug("can't find the block"); - return -3; - } - - - payData.balance = block.getInfo().getAmount(); - - - if (compareAmountTo(payData.balance,XAmount.ZERO) <= 0) { - log.debug("no main block,can't pay"); - return -5; - } - - // 计算矿池部分的收益 - payData.poolFee = payData.balance.multiply(poolRation); - payData.unusedBalance = payData.balance.subtract(payData.poolFee); - - // 进行各部分奖励的计算 - if (compareAmountTo(payData.unusedBalance,XAmount.ZERO) <= 0) { - log.debug("Balance no enough"); - return -6; - } - - if (keyPos < 0) { - log.debug("can't find the key"); - return -7; - } - - // 决定一个区块是否需要再有一个签名字段 - // todo 这里不够严谨把 如果时第三把第四把呢 - if (wallet.getAccounts().size() - 1 == keyPos) { - payminersPerBlock = 11; - } else { - payminersPerBlock = 9; - } - - diff = new ArrayList<>(minerCounts); - prev_diff = new ArrayList<>(minerCounts); - Collections.fill(diff, 0.0); - Collections.fill(prev_diff, 0.0); - double prevDiffSum = precalculatePayments(nonce, index, payData); - - log.debug("after cal prevdiffSum为[{}]", prevDiffSum); - if (prevDiffSum <= DBL) { - log.debug("diff is too low"); - return -8; - } - - // 通过precalculatePay后计算出的数据 进行计算 - doPayments(hashlow, payminersPerBlock, payData, keyPos); - log.debug("=========== end payMiners for time [{}]===========", time); - return 0; - } - - private double precalculatePayments(Bytes32 nonce, int index, PayData payData) { - log.debug("precalculatePayments........"); - - // 说明需要支付给基金会 - if (fundRation != 0) { - payData.fundIncome = payData.balance.multiply(fundRation); - payData.unusedBalance = payData.unusedBalance.subtract(payData.fundIncome); - } - - - //这里缺少对矿池的计算 - //现对矿池进行计算 - payData.prevDiffSums = countpay(poolMiner, index, payData); - - //遍历每一个矿工进行运行 获取到对应的数据 - for (int i = 0; i < miners.size(); i++) { - Miner miner = miners.get(i); - prev_diff.add(i, countpay(miner, index, i)); - - payData.diffSums += diff.get(i); - payData.prevDiffSums += prev_diff.get(i); - - if (payData.rewardMiner == null - && (compareTo(nonce.toArray(), 0, 20, miner.getAddressHashByte(), 0, 20) == 0)) { - payData.rewardMiner = new byte[32]; - payData.rewardMiner = miner.getAddressHash().toArray(); - // 有可以出块的矿工 分配矿工的奖励 - payData.minerReward = payData.balance.multiply(minerRewardRation); - payData.unusedBalance = payData.unusedBalance.subtract(payData.minerReward); - } - } - - for (Map.Entry entry : minerManager.getActivateMinerChannels().entrySet()) { - MinerChannel channel = entry.getValue(); - if (channel.getMaxDiffs(index) > 0) { - channel.addMaxDiffs(index, 0); - } - channel.setPrevDiff(0.0); - channel.setPrevDiffCounts(0); - } - - // 要进行参与奖励的支付 - if (payData.diffSums > 0) { - payData.directIncome = payData.balance.multiply(directRation); - payData.unusedBalance = payData.unusedBalance.subtract(payData.directIncome); - } - return payData.prevDiffSums; - } - - /** - * 对矿工之前的挖矿的难度进行计算 主要是用于形成支付的权重 - * - * @param miner 矿工的结构体 - * @param index 对应的要计算的难度编号 - */ - private Double countpay(Miner miner, int index, int i) { - double diffSum = 0.0; - int diffCount = 0; - // 这里是如果矿工的 - if (miner.getMinerStates() == MinerStates.MINER_ARCHIVE - && - // c好过十六个时间戳没有进行计算 - currentTaskIndex - miner.getTaskIndex() > 16) { - // 这个主要是为了超过十六个快没有挖矿 所以要给他支付 - diffSum += processOutdatedMiner(miner); - diffCount++; - } else if (miner.getMaxDiffs(index) > 0) { - diffSum += miner.getMaxDiffs(index); - miner.setMaxDiffs(index, 0.0); - ++diffCount; - } - diff.add(i, diffToPay(diffSum, diffCount)); - diffSum += miner.getPrevDiff(); - diffCount += miner.getPrevDiffCounts(); - - miner.setPrevDiff(0.0); - miner.setPrevDiffCounts(0); - - return diffToPay(diffSum, diffCount); - - } - - private Double countpay(Miner miner, int index, PayData payData) { - double diffSum = 0.0; - int diffCount = 0; - // 这里是如果矿工的 - if (miner.getMinerStates() == MinerStates.MINER_ARCHIVE - && - // c好过十六个时间戳没有进行计算 - currentTaskIndex - miner.getTaskIndex() > 16) { - // 这个主要是为了超过十六个快没有挖矿 所以要给他支付 - diffSum += processOutdatedMiner(miner); - diffCount++; - } else if (miner.getMaxDiffs(index) > 0) { - diffSum += miner.getMaxDiffs(index); - miner.setMaxDiffs(index, 0.0); - ++diffCount; - } - - payData.diffSums = diffToPay(diffSum, diffCount); - diffSum += miner.getPrevDiff(); - diffCount += miner.getPrevDiffCounts(); - - miner.setPrevDiff(0.0); - miner.setPrevDiffCounts(0); - - return diffToPay(diffSum, diffCount); - - } - - public void doPayments(Bytes32 hashLow, int paymentsPerBlock, PayData payData, int keyPos) { - log.debug("Do payment"); - ArrayList
receipt = new ArrayList<>(paymentsPerBlock - 1); - XAmount payAmount = XAmount.ZERO; - //计算发给所有矿工的总额,用来计算矿池自身最终所得 - XAmount paySum = XAmount.ZERO; - - /* - * 基金会和转账矿池部分代码 暂时不用 //先支付给基金会 long fundpay = - * BasicUtils.xdag2amount(payData.fundIncome); byte[] fund = - * BytesUtils.fixBytes(BasicUtils.address2Hash(Constants.FUND_ADDRESS),8,24); - * - *

- * receipt.add(new - * Address(fund,XDAG_FIELD_OUT,BasicUtils.xdag2amount(payData.fundIncome))); - * payAmount += payData.fundIncome; - * - *

- * //支付给矿池 实际上放着不动 就属于矿池 receipt.add(new - * Address(poolMiner.getAddressLow(),XDAG_FIELD_OUT,payData.poolFee)); payAmount - * += payData.poolFee; - */ - if (fundRation!=0) { - if (WalletUtils.checkAddress(fundAddress)) { - payAmount = payAmount.add(payData.fundIncome); - receipt.add(new Address(pubAddress2Hash(fundAddress), XDAG_FIELD_OUTPUT, payData.fundIncome,true)); - } - } - - // 不断循环 支付给矿工 - //// TODO: 2021/4/19 打印矿工的数据 - for (int i = 0; i < miners.size(); i++) { - Miner miner = miners.get(i); - log.debug("Do payments for every miner,miner address = [{}]", WalletUtils.toBase58(miner.getAddressHashByte())); - // 保存的是一个矿工所有的收入 - XAmount paymentSum = XAmount.ZERO; - // 根据历史记录分发奖励 - if (payData.prevDiffSums > 0) { - double per = BigDecimalUtils.divAndDown(prev_diff.get(i), payData.prevDiffSums, 8); - // paymentSum += (long)payData.unusedBalance * per; - paymentSum = paymentSum.add(payData.unusedBalance.multiply(per)); - } - // 计算当前这一轮 - if (payData.diffSums > 0) { - double per = BigDecimalUtils.divAndDown(diff.get(i), payData.diffSums, 8); - // paymentSum += (long)payData.directIncome * per; - paymentSum = paymentSum.add(payData.directIncome.multiply(per)); - } - if (payData.rewardMiner != null - && compareTo(payData.rewardMiner, 8, 24, miner.getAddressHash().toArray(), 8, 24) == 0) { - paymentSum = paymentSum.add(payData.minerReward); - } - // TODO new XAmount must be testing by holt666 - if (compareAmountTo(paymentSum,XAmount.of(42590)) < 0) { - continue; - } - payAmount = payAmount.add(paymentSum); - receipt.add(new Address(miner.getAddressHash(), XDAG_FIELD_OUTPUT, paymentSum,true)); - - paySum = paySum.add(paymentSum); - if (receipt.size() == paymentsPerBlock) { - - transaction(hashLow, receipt, payAmount, keyPos); - payAmount = XAmount.ZERO; - receipt.clear(); - } - } - - //给矿池主奖励 - XAmount poolAmount = payData.balance.subtract(payData.fundIncome).subtract(paySum); - if (poolAmount.compareTo(XAmount.ZERO) > 0) { - receipt.add(new Address(blockchain.getBlockByHash(hashLow,true).getCoinBase().getAddress(),XDAG_FIELD_OUTPUT,poolAmount,true)); - payAmount = payAmount.add(poolAmount); - } - - transaction(hashLow, receipt, payAmount, keyPos); - receipt.clear(); - } - - public void transaction(Bytes32 hashLow, ArrayList

receipt, XAmount payAmount, int keypos) { - log.debug("All Payment: {}", payAmount); - log.debug("unlock keypos =[{}]", keypos); - for (Address address : receipt) { - log.debug("pay data: {}", address.getData().toHexString()); - } - Map inputMap = new HashMap<>(); - Address input = new Address(hashLow, XDAG_FIELD_IN, payAmount,false); - KeyPair inputKey = wallet.getAccount(keypos); - inputMap.put(input, inputKey); - Block block = blockchain.createNewBlock(inputMap, receipt, false, null); - if (inputKey.equals(wallet.getDefKey())) { - block.signOut(inputKey); - } else { - block.signIn(inputKey); - block.signOut(wallet.getDefKey()); - } - log.debug("pay block hash [{}]", block.getHash().toHexString()); - - // todo 需要验证还是直接connect - kernel.getSyncMgr().validateAndAddNewBlock(new BlockWrapper(block, 5)); - } - - /** - * 内部类 用于计算支付数据 - */ - public static class PayData { - - // 整个区块用于支付的金额 - XAmount balance = XAmount.ZERO; - // 每一次扣除后剩余的钱 回合所用矿工平分 - XAmount unusedBalance = XAmount.ZERO; - // 矿池自己的收入 - XAmount poolFee = XAmount.ZERO; - // 出块矿工的奖励 - XAmount minerReward = XAmount.ZERO; - // 参与挖矿的奖励 - XAmount directIncome = XAmount.ZERO; - // 基金会的奖励 - XAmount fundIncome = XAmount.ZERO; - // 所有矿工diff 的难度之和 - double diffSums; - // 所有矿工prevdiff的难度之和 - double prevDiffSums; - // 记录奖励矿工的位置 - byte[] rewardMiner = null; - } - - - /** - * 用于记录奖励主块的信息 - */ - public static class AwardBlock { - - Bytes32 share; - Bytes32 hash; - long generateTime; - } -} diff --git a/src/main/java/io/xdag/mine/manager/MinerManagerImpl.java b/src/main/java/io/xdag/mine/manager/MinerManagerImpl.java deleted file mode 100644 index b1775f25d..000000000 --- a/src/main/java/io/xdag/mine/manager/MinerManagerImpl.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.manager; - -import io.xdag.Kernel; -import io.xdag.consensus.PoW; -import io.xdag.consensus.Task; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerStates; -import io.xdag.net.message.Message; -import java.net.InetSocketAddress; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; -import org.apache.tuweni.bytes.Bytes; - -@Slf4j -public class MinerManagerImpl implements MinerManager, Runnable { - - /** - * 存放任务的阻塞队列 - */ - private final BlockingQueue taskQueue = new LinkedBlockingQueue<>(100); - private final Kernel kernel; - private final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(3, new BasicThreadFactory.Builder() - .namingPattern("MinerManager-Scheduled-Thread-%d") - .daemon(true) - .build()); - - private final ExecutorService mainExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder() - .namingPattern("MinerManager-Main-Thread-%d") - .daemon(true) - .build()); - - private final ExecutorService workerExecutor = Executors.newCachedThreadPool(new BasicThreadFactory.Builder() - .namingPattern("MinerManager-Worker-Thread-%d") - .daemon(true) - .build()); - - private volatile boolean isRunning = false; - /** - * 保存活跃的channel - */ - protected Map activateMinerChannels = new ConcurrentHashMap<>(); - private int activateMinerChannelsSize; - /** - * 根据miner的地址保存的数组 activate 代表的是一个已经注册的矿工 - */ - protected final Map activateMiners = new ConcurrentHashMap<>(200); - private volatile Task currentTask; - @Setter - private PoW poW; - private ScheduledFuture cleanChannelFuture; - private ScheduledFuture cleanMinerFuture; - - public MinerManagerImpl(Kernel kernel) { - this.kernel = kernel; - } - - private final Object obj1 = new Object(); - private final Object obj2 = new Object(); - - @Override - public void run() { - while (isRunning) { - updateNewTaskandBroadcast(); - } - } - - @Override - public void start() { - isRunning = true; - init(); - mainExecutor.execute(this); - log.debug("MinerManager started."); - } - - @Override - public void stop() { - isRunning = false; - close(); - log.debug("MinerManager closed."); - } - - /** - * 启动 函数 开启遍历和server - */ - public void init() { - cleanChannelFuture = scheduledExecutor.scheduleAtFixedRate(this::cleanUnactivateChannel, 64, 32, TimeUnit.SECONDS); - cleanMinerFuture = scheduledExecutor.scheduleAtFixedRate(this::cleanUnactivateMiner, 64, 32, TimeUnit.SECONDS); - } - - @Override - public void addActivateChannel(MinerChannel channel) { - log.debug("add a new active channel"); - synchronized (obj1) { - activateMinerChannels.put(channel.getInetAddress(), channel); - activateMinerChannelsSize ++; - } - } - - public void close() { - - if (cleanChannelFuture != null) { - cleanChannelFuture.cancel(true); - } - if (cleanMinerFuture != null) { - cleanMinerFuture.cancel(true); - } - mainExecutor.shutdown(); - scheduledExecutor.shutdown(); - closeMiners(); - } - - private void closeMiners() { - synchronized (obj1) { - activateMinerChannels.values().forEach( - mc -> workerExecutor.submit(mc::dropConnection) - ); - } - } - - @Override - public void removeUnactivateChannel(MinerChannel channel) { - if (channel != null && !channel.isActive()) { - log.debug("remove a channel"); - kernel.getChannelsAccount().getAndDecrement(); - activateMinerChannels.remove(channel.getInetAddress(), channel); - activateMinerChannelsSize --; - synchronized (obj2) { - Miner miner = activateMiners.get(Bytes.of(channel.getAccountAddressHash().toArray())); - if (miner == null) { - return; - } - miner.removeChannel(channel.getInetAddress()); - if (miner.getChannels().size() == 0) { - log.debug("a mine remark MINER_ARCHIVE,miner Address=[{}] ", miner.getAddressHash().toHexString()); - miner.setMinerStates(MinerStates.MINER_ARCHIVE); - } - } - } - } - - public void cleanUnactivateChannel() { - synchronized (obj1) { - try { - activateMinerChannels.values().forEach( - mc -> workerExecutor.submit(() -> removeUnactivateChannel(mc)) - ); - } catch (Exception e) { - log.error("An exception occurred in cleanUnactivateChannel: Exception->{}", e.getMessage(), e); - } - } - } - - public void cleanUnactivateMiner() { - synchronized (obj2) { - try { - activateMiners.entrySet().removeIf(entry -> entry.getValue().canRemove()); - } catch (Exception e) { - log.error("An exception occurred in cleanUnactivateMiner: Exception->{}", e.getMessage(), e); - } - } - } - - @Override - public void updateTask(Task task) { - if (!taskQueue.offer(task)) { - log.debug("Failed to add a task to the queue!"); - } - } - - @Override - public void addActiveMiner(Miner miner) { - synchronized (obj2) { - activateMiners.put(miner.getAddressHash(), miner); - } - } - - /** - * When each round of tasks is just sent out, this will be used to update all miner's status - */ - public void updateNewTaskandBroadcast() { - Task task = null; - try { - task = taskQueue.poll(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - log.error(" can not take the task from taskQueue" + e.getMessage(), e); - } - if (task != null) { - currentTask = task; - synchronized (obj1) { - log.debug("Now activateMiners size:{}",activateMiners.size()); - log.debug("the size of active miner channels:{}", activateMinerChannelsSize); - activateMinerChannels.values().stream() - .filter(MinerChannel::isActive) - .forEach(c -> workerExecutor.submit(() -> { - c.setTaskIndex(currentTask.getTaskIndex()); - c.sendTaskToMiner(currentTask.getTask()); - c.setSharesCounts(0); - log.debug("Send task:{},task time:{},task index:{}, to address: {} ip&port:{}", - Bytes.wrap(currentTask.getTask()[0].getData(), currentTask.getTask()[1].getData()).toHexString(), - currentTask.getTaskTime(),currentTask.getTaskIndex(),c.getAddressHash(),c.getInetAddress().toString()); - })); - } - } - } - - @Override - public Map getActivateMiners() { - return activateMiners; - } - - @Override - public void onNewShare(MinerChannel channel, Message msg) { - if (currentTask == null) { - log.info("currentTask is empty"); - } else if (currentTask.getTaskIndex() == channel.getTaskIndex()) { - poW.receiveNewShare(channel, msg); - } - } - - @Override - public MinerChannel getChannelByHost(InetSocketAddress host) { - return this.activateMinerChannels.get(host); - } - - @Override - public Map getActivateMinerChannels() { - return this.activateMinerChannels; - } -} diff --git a/src/main/java/io/xdag/mine/message/MinerMessageFactory.java b/src/main/java/io/xdag/mine/message/MinerMessageFactory.java deleted file mode 100644 index 3c6ff9136..000000000 --- a/src/main/java/io/xdag/mine/message/MinerMessageFactory.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.message; - -import io.xdag.net.XdagVersion; -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageFactory; -import io.xdag.net.message.XdagMessageCodes; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.MutableBytes; - -@Slf4j -public class MinerMessageFactory implements MessageFactory { - - @Override - public Message create(byte code, MutableBytes encoded) { - // 从当前版本中获取到有用的信息 - XdagMessageCodes receivedCommand = XdagMessageCodes.fromByte(code, XdagVersion.V03); - switch (receivedCommand) { - case TASK_SHARE -> { - return new TaskShareMessage(encoded); - } - case NEW_TASK -> { - return new NewTaskMessage(encoded); - } - case NEW_BALANCE -> { - return new NewBalanceMessage(encoded); - } - case WORKER_NAME -> { - return new WorkerNameMessage(encoded); - } - default -> { - log.debug(encoded.toHexString()); - throw new IllegalArgumentException("No such message code" + receivedCommand); - } - } - } -} diff --git a/src/main/java/io/xdag/mine/miner/Miner.java b/src/main/java/io/xdag/mine/miner/Miner.java deleted file mode 100644 index d988ff7c2..000000000 --- a/src/main/java/io/xdag/mine/miner/Miner.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.miner; - -import io.xdag.mine.MinerChannel; -import io.xdag.utils.BytesUtils; - -import java.net.InetSocketAddress; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; - -import io.xdag.utils.WalletUtils; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes32; - -@Slf4j -public class Miner { - - /** - * 保存这个矿工的地址 - */ - private final Bytes32 addressHash; - - @Getter - private final byte[] addressHashByte; - /** - * 相同账户地址的channel数量 - */ - private final AtomicInteger connChannelCounts = new AtomicInteger(0); - /** - * 存放的是连续16个任务本地计算的最大难度 每一轮放的都是最小hash 计算出来的diffs - */ - private final List maxDiffs = new CopyOnWriteArrayList<>(); - - /** - * 保存的是这个矿工对应的channel - */ - private final Map channels = new ConcurrentHashMap<>(); - - protected int boundedTaskCounter; - /** - * 记录收到任务的时间 - */ - private long taskTime; - @Getter - @Setter - /* 记录任务索引 * */ - private long taskIndex; - /** - * 记录的是当前任务所有难度之和,每当接收到一个新的nonce 会更新这个 - */ - private double prevDiff; - /** - * 记录prevDiff的次数 实际上类似于进行了多少次计算 - */ - private int prevDiffCounts; - /** - * 记录这个矿工的状态 - */ - private MinerStates minerStates; - /** - * 类似于id 也是保存的nonce +hasholow的值 - */ - @Getter - @Setter - private Bytes32 nonce; - /** - * 记录上一轮任务中最小的hash - */ - private Bytes32 lastMinHash; - /** - * 将hash转换后的难度 可以认为是算力 - */ - private double meanLogDiff; - private Date registeredTime; - - public Miner(Bytes32 addressHash) { - log.debug("init the new miner:{}", addressHash.toHexString()); - this.addressHash = addressHash; - addressHashByte = BytesUtils.byte32ToArray(addressHash.mutableCopy()); - this.minerStates = MinerStates.MINER_UNKNOWN; - this.taskTime = 0; - this.meanLogDiff = 0.0; - this.registeredTime = Calendar.getInstance().getTime(); - boundedTaskCounter = 0; - // 容器的初始化 - for (int i = 0; i < 16; i++) { - maxDiffs.add(0.0); - } - } - - public Bytes32 getAddressHash() { - return this.addressHash; - } - - public int getConnChannelCounts() { - return connChannelCounts.get(); - } - - public MinerStates getMinerStates() { - return this.minerStates; - } - - public void setMinerStates(MinerStates states) { - this.minerStates = states; - } - - /** - * 判断这个miner 是不是可以被移除 - * 没有矿机接入 - * 状态等于归档 - * maxdiff 全部为0 - */ - public boolean canRemove() { - if (minerStates == MinerStates.MINER_ARCHIVE && channels.size() == 0) { - for (Double maxDiff : maxDiffs) { - if (maxDiff.compareTo((double) 0) > 0) { - return false; - } - } - log.debug("remove Miner: {}", WalletUtils.toBase58(addressHashByte)); - return true; - } else { - return false; - } - } - - public long getTaskTime() { - return this.taskTime; - } - - public void setTaskTime(long time) { - this.taskTime = time; - } - - public double getMaxDiffs(int index) { - return maxDiffs.get(index); - } - - public void addPrevDiff(double i) { - prevDiff += i; - } - - public void addPrevDiffCounts() { - this.prevDiffCounts++; - } - - public void setMaxDiffs(int index, double diff) { - maxDiffs.set(index, diff); - } - - public double getPrevDiff() { - return prevDiff; - } - - public void setPrevDiff(double i) { - this.prevDiff = i; - } - - public int getPrevDiffCounts() { - return prevDiffCounts; - } - - public void setPrevDiffCounts(int i) { - this.prevDiffCounts = i; - } - - public Date getRegTime() { - return registeredTime; - } - - public Map getChannels() { - return channels; - } - - public double getMeanLogDiff() { - return this.meanLogDiff; - } - - public void setMeanLogDiff(double meanLogDiff) { - this.meanLogDiff = meanLogDiff; - } - - public Bytes32 getLastMinHash() { - return lastMinHash; - } - - public void setLastMinHash(Bytes32 lastMinHash) { - this.lastMinHash = lastMinHash; - } - - public int getBoundedTaskCounter() { - return boundedTaskCounter; - } - - public void addBoundedTaskCounter() { - this.boundedTaskCounter++; - } - - public void putChannel(InetSocketAddress inetSocketAddress, MinerChannel channel) { - this.channels.put(inetSocketAddress, channel); - connChannelCounts.incrementAndGet(); - } - - public void removeChannel(InetSocketAddress address) { - this.channels.remove(address); - connChannelCounts.getAndDecrement(); - } -} diff --git a/src/main/java/io/xdag/mine/miner/MinerCalculate.java b/src/main/java/io/xdag/mine/miner/MinerCalculate.java deleted file mode 100644 index dbfaca4db..000000000 --- a/src/main/java/io/xdag/mine/miner/MinerCalculate.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.miner; - -import static io.xdag.utils.BytesUtils.compareTo; -import static java.lang.Math.E; - -import io.xdag.config.Config; -import io.xdag.config.Constants; -import io.xdag.consensus.Task; -import io.xdag.mine.MinerChannel; -import io.xdag.utils.BasicUtils; -import io.xdag.utils.BigDecimalUtils; -import io.xdag.utils.BytesUtils; -import io.xdag.utils.WalletUtils; -import io.xdag.utils.XdagTime; -import java.net.InetSocketAddress; -import java.util.Map; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes32; - -@Slf4j -public class MinerCalculate { - - private static final int NSAMPLES_MAX = 255; - - /** - * 每一轮的确认数是16 - */ - private static final int CONFIRMATIONS_COUNT = Constants.CONFIRMATIONS_COUNT; - - /** - * 实现一个由难度转换为pay 的函数 - */ - public static double diffToPay(double sum, int diffCount) { - double result = 0.0; - if (diffCount > 0) { - result = Math.pow(E, ((sum / diffCount) - 20)) * diffCount; - } - return result; - } - - /** - * 用于打印矿工但钱未支付的难度总和 - */ - public static double calculateUnpaidShares(Miner miner) { - double sum = miner.getPrevDiff(); - int count = miner.getPrevDiffCounts(); - for (int i = 0; i < CONFIRMATIONS_COUNT; i++) { - if (miner.getMaxDiffs(i) > 0) { - sum = BigDecimalUtils.add(sum, miner.getMaxDiffs(i)); - ++count; - } - } - return diffToPay(sum, count); - } - - public static double calculateUnpaidShares(MinerChannel channel) { - double sum = channel.getPrevDiff(); - int count = channel.getPrevDiffCounts(); - for (int i = 0; i < CONFIRMATIONS_COUNT; i++) { - if (channel.getMaxDiffs(i) > 0) { - sum = BigDecimalUtils.add(sum, channel.getMaxDiffs(i)); - ++count; - } - } - log.debug("print unpaid for miner: {} , sum= [{}] , count = [{}]", - WalletUtils.toBase58(channel.getMiner().getAddressHashByte()),sum, count); - return diffToPay(sum, count); - } - - public static String minerStats(Miner miner) { - StringBuilder res = new StringBuilder(); - String address = WalletUtils.toBase58(miner.getAddressHashByte()); - double unpaid = calculateUnpaidShares(miner); - String minerRegTime = XdagTime.format(miner.getRegTime()); - res.append("miner: ") - .append(address) - .append(" regTime: ") - .append(minerRegTime) - .append(" unpaid: ") - .append(String.format("%.6f", unpaid)) - .append(" HashRate: ") - .append(String.format("%.6f", BasicUtils.xdag_log_difficulty2hashrate(miner.getMeanLogDiff()))) - .append("\n"); - - Map channels = miner.getChannels(); - // todo 给每一个channels 加上一个单独的语句 - for (MinerChannel channel : channels.values()) { - StringBuilder channelStr = new StringBuilder(); - String connTime = XdagTime.format(channel.getConnectTime()); - String ip = channel.getInetAddress().toString(); - double unpaidChannel = calculateUnpaidShares(channel); - - double mean = channel.getMeanLogDiff(); - log.debug("print unpaid = [{}], meanlog = [{}] for miner: {} ", - unpaidChannel, mean ,channel.getAddressHash()); - double rate = BasicUtils.xdag_log_difficulty2hashrate(mean); - - channelStr - .append("WorkerName: ") - .append(channel.getWorkerName()) - .append(" ") - .append("ip: ") - .append(ip) - .append(" ") - .append("connTime: ") - .append(connTime) - .append(" ") - .append("unpaid: ") - .append(String.format("%.6f", unpaidChannel)) - .append(" ") - .append("HashRate: ") - .append(String.format("%.6f", rate)) - .append(" ") - .append("RandomXMiner") - .append("\n"); - res.append(channelStr); - } - return res.toString(); - } - - /** - * 根据一个矿工计算的hash 为他计算一个难度 - */ - public static void calculateNopaidShares( - Config config, MinerChannel channel, Bytes32 hash, long currentTaskTime) { - Miner miner = channel.getMiner(); - double diff; - // 不可能出现大于的情况 防止对老的任务重复计算 - long minerTaskTime = miner.getTaskTime(); - long channelTaskTime = channel.getTaskTime(); - log.debug( - "CalculateNoPaidShares for miner: {},currentTaskTime = [{}],miner tasktime = [{}],channelTaskTime = [{}]", - channel.getAddressHash(), currentTaskTime, minerTaskTime, channelTaskTime); - if (channelTaskTime <= currentTaskTime) { - // 获取到位置 myron - int i = (int) (((currentTaskTime >> 16) + 1) & config.getPoolSpec().getAwardEpoch()); - diff = BytesUtils.hexBytesToDouble(hash.toArray(), 8, false); - diff *= Math.pow(2, -64); - diff += BytesUtils.hexBytesToDouble(hash.toArray(), 0, false); - - if (diff < 1) { - diff = 1; - } - diff = 46 - Math.log(diff); - log.debug("CalculateNoPaidShares for miner: {}, latest diff is [{}]", - channel.getAddressHash(), diff); - if (channelTaskTime < currentTaskTime) { - channel.setTaskTime(currentTaskTime); - double maxDiff = channel.getMaxDiffs(i); - log.debug("CalculateNoPaidShares for miner: {},channel get maxDiff at first is [{}] = [{}]", - channel.getAddressHash(), i, maxDiff); - if (maxDiff > 0) { - - channel.addPrevDiff(maxDiff); - channel.addPrevDiffCounts(); - } - channel.addMaxDiffs(i, diff); - } else if (diff > channel.getMaxDiffs(i)) { - log.debug("CalculateNoPaidShares for miner: {},channel get the maxDiff[{}] = [{}]", - channel.getAddressHash(), i, diff); - channel.addMaxDiffs(i, diff); - } - // 给对应的矿工设置 - if (minerTaskTime < currentTaskTime) { - miner.setTaskTime(currentTaskTime); - double maxDiff = miner.getMaxDiffs(i); - log.debug("CalculateNoPaidShares for miner: {}, channel get the maxdiff[{}] = [{}]", - channel.getAddressHash(), i, maxDiff); - if (maxDiff > 0) { - miner.addPrevDiff(maxDiff); - miner.addPrevDiffCounts(); - } - miner.setMaxDiffs(i, diff); - } else if (diff > miner.getMaxDiffs(i)) { - miner.setMaxDiffs(i, diff); - } - } - } - - public static double welfordOnePass(double mean, double sample, int nsamples) { - if (nsamples > 0) { - double temp = BigDecimalUtils.div(BigDecimalUtils.sub(sample, mean), nsamples); - mean = BigDecimalUtils.add(mean, temp); - } - return mean; - } - - public static double movingAverageDouble(double mean, double sample, int nsamples) { - if (nsamples < 2) { - mean = sample; - } - if (nsamples >= NSAMPLES_MAX) { - mean = welfordOnePass(mean, sample, NSAMPLES_MAX); - } else { - mean = welfordOnePass(mean, sample, nsamples); - } - return mean; - } - - /** - * 更新矿工的meanlog - * - * @param channel 对应的矿工 - * @param task 当前的任务 - * @param hash 接收到矿工发送的share后计算的hash - */ - public static void updateMeanLogDiff(MinerChannel channel, Task task, Bytes32 hash) { - log.debug("Receive a Share message from miner : {} and update the message of the corresponding channel", - channel.getAddressHash()); - log.debug("The hash calculated by miner:{} is [{}]", - channel.getAddressHash(),hash.toHexString()); - long taskTime = task.getTaskTime(); - long channelTime = channel.getTaskTime(); - if (channelTime < taskTime) { - if (channelTime != 0) { - double meanLogDiff = movingAverageDouble( - channel.getMeanLogDiff(), - BasicUtils.xdag_diff2log(BasicUtils.getDiffByHash(channel.getMinHash())), - channel.getBoundedTaskCounter()); - channel.setMeanLogDiff(meanLogDiff); - log.debug("channel updateMeanLogDiff [{}] for miner: {}", - channel.getMeanLogDiff(),channel.getAddressHash()); - if (channel.getBoundedTaskCounter() < NSAMPLES_MAX) { - channel.addBoundedTaskCounter(); - } - } - channel.setMinHash(hash); - } else if (compareTo(hash.toArray(), 0, hash.size(), channel.getMinHash().toArray(), 0, hash.size()) < 0) { - channel.setMinHash(hash); - } - - Miner miner = channel.getMiner(); - long minerTaskTime = miner.getTaskTime(); - if (minerTaskTime < taskTime) { - if (minerTaskTime != 0) { - double meanLogDiff = movingAverageDouble( - miner.getMeanLogDiff(), - BasicUtils.xdag_diff2log(BasicUtils.getDiffByHash(miner.getLastMinHash())), - miner.getBoundedTaskCounter()); - - log.debug("miner: {} updateMeanLogDiff [{}]", - BasicUtils.hash2Address(miner.getAddressHash()), meanLogDiff); - miner.setMeanLogDiff(meanLogDiff); - //log.debug("miner updateMeanLogDiff [{}]", miner.getMeanLogDiff()); - - if (miner.boundedTaskCounter < NSAMPLES_MAX) { - miner.addBoundedTaskCounter(); - } - } - miner.setLastMinHash(hash); - } else if (compareTo(hash.toArray(), 0, hash.size(), miner.getLastMinHash().toArray(), 0, hash.size()) < 0) { - miner.setLastMinHash(hash); - } - } - - -} diff --git a/src/main/java/io/xdag/mine/miner/MinerStates.java b/src/main/java/io/xdag/mine/miner/MinerStates.java deleted file mode 100644 index 9ec81c871..000000000 --- a/src/main/java/io/xdag/mine/miner/MinerStates.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.miner; - -public enum MinerStates { - - /** - * 未知 表示当前矿工还为注册 - */ - MINER_UNKNOWN(0x00), - /** - * 活跃 矿工已经注册 且持续工作 - */ - MINER_ACTIVE(0x01), - /** - * 矿工已经注册,但是没有在挖矿 仅仅是因为还有未支付的余额所以保留档案 - */ - MINER_ARCHIVE(0x02), - /** - * 服务端 表示这个矿工对象是一个矿池 - */ - MINER_SERVICE(0x03); - - private final int cmd; - - MinerStates(int cmd) { - this.cmd = cmd; - } - - public static MinerStates fromByte(byte i) throws Exception { - return switch ((int) i) { - case 0x00 -> MINER_UNKNOWN; - case 0x01 -> MINER_ACTIVE; - case 0x02 -> MINER_ARCHIVE; - case 0x03 -> MINER_SERVICE; - default -> throw new Exception("can find the miner state......please check the param!!"); - }; - } - - public byte asByte() { - return (byte) (cmd); - } - - @Override - public String toString() { - return switch (cmd) { - case 0x00 -> "MINER_UNKNOWN"; - case 0x01 -> "MINER_ACTIVE"; - case 0x02 -> "MINER_ARCHIVE"; - case 0x03 -> "MINER_SERVICE"; - default -> "can find the miner state......please check the param!!"; - }; - } -} diff --git a/src/main/java/io/xdag/crypto/DnetKeys.java b/src/main/java/io/xdag/net/Capability.java similarity index 77% rename from src/main/java/io/xdag/crypto/DnetKeys.java rename to src/main/java/io/xdag/net/Capability.java index c29e4d306..9e5e5159f 100644 --- a/src/main/java/io/xdag/crypto/DnetKeys.java +++ b/src/main/java/io/xdag/net/Capability.java @@ -21,21 +21,24 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net; -package io.xdag.crypto; +public enum Capability { + /** + * full node. + */ + FULL_NODE, + /** + * light node. + */ + LIGHT_NODE; -public class DnetKeys { - - public byte[] prv; - public byte[] pub; - - public byte[] sect0_encoded; - public byte[] sect0; - - public DnetKeys() { - prv = new byte[1024]; - pub = new byte[1024]; - sect0_encoded = new byte[512]; - sect0 = new byte[512]; + public static Capability of(String name) { + try { + return valueOf(name); + } catch (IllegalArgumentException | NullPointerException ex) { + return null; + } } + } diff --git a/src/main/java/io/xdag/net/CapabilityTreeSet.java b/src/main/java/io/xdag/net/CapabilityTreeSet.java new file mode 100644 index 000000000..4df9dcc4b --- /dev/null +++ b/src/main/java/io/xdag/net/CapabilityTreeSet.java @@ -0,0 +1,115 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CapabilityTreeSet { + + private final TreeSet capabilities; + + private CapabilityTreeSet(Collection capabilities) { + this.capabilities = new TreeSet<>(capabilities); + } + + /** + * Creates an empty set. + */ + public static CapabilityTreeSet emptyList() { + return new CapabilityTreeSet(Collections.emptyList()); + } + + /** + * Converts an array of capability into capability set. + * + * @param capabilities + * the specified capabilities + */ + public static CapabilityTreeSet of(Capability... capabilities) { + return new CapabilityTreeSet(Stream.of(capabilities).filter(Objects::nonNull).collect(Collectors.toList())); + } + + /** + * Converts an array of capability into capability set. + * + * @param capabilities + * the specified capabilities + * @ImplNode unknown capabilities are ignored + */ + public static CapabilityTreeSet of(String... capabilities) { + return new CapabilityTreeSet( + Stream.of(capabilities).map(Capability::of).filter(Objects::nonNull).collect(Collectors.toList())); + } + + /** + * Checks whether the capability is supported by the ${@link CapabilityTreeSet}. + * + * @param capability + * the capability to be checked. + * @return true if the capability is supported, false if not + */ + public boolean isSupported(Capability capability) { + return capabilities.contains(capability); + } + + /** + * Returns the size of the capability set. + */ + public int size() { + return capabilities.size(); + } + + /** + * Converts the capability set to an list of String. + */ + public List toList() { + return capabilities.stream().map(Capability::name).collect(Collectors.toList()); + } + + /** + * Converts the capability set to an array of String. + */ + public String[] toArray() { + return capabilities.stream().map(Capability::name).toArray(String[]::new); + } + + @Override + public boolean equals(Object object) { + return object instanceof CapabilityTreeSet + && Arrays.equals(toArray(), ((CapabilityTreeSet) object).toArray()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(toArray()); + } + +} diff --git a/src/main/java/io/xdag/net/Channel.java b/src/main/java/io/xdag/net/Channel.java index f8997f2ca..378607216 100644 --- a/src/main/java/io/xdag/net/Channel.java +++ b/src/main/java/io/xdag/net/Channel.java @@ -24,13 +24,15 @@ package io.xdag.net; +import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; +import io.netty.handler.timeout.ReadTimeoutHandler; import io.xdag.Kernel; -import io.xdag.core.BlockWrapper; -import io.xdag.net.handler.Xdag; import io.xdag.net.message.MessageQueue; import io.xdag.net.node.Node; import java.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; + import lombok.Getter; import lombok.Setter; @@ -39,35 +41,85 @@ */ @Getter @Setter -public abstract class Channel { +public class Channel { + + private SocketChannel socket; + private boolean isInbound; + private InetSocketAddress remoteAddress; + private Peer remotePeer; + private MessageQueue msgQueue; + private boolean isActive; + private XdagP2pHandler p2pHandler; + + /** + * Creates a new channel instance. + */ + public Channel(SocketChannel socket) { + this.socket = socket; + } + + /** + * Initializes this channel. + */ + public void init(ChannelPipeline pipe, boolean isInbound, InetSocketAddress remoteAddress, Kernel kernel) { + this.isInbound = isInbound; + this.remoteAddress = remoteAddress; + this.remotePeer = null; - protected SocketChannel socketChannel; - protected InetSocketAddress inetSocketAddress; - protected Node node; - protected MessageQueue messageQueue; - protected Kernel kernel; - protected boolean isActive; - protected boolean isDisconnected = false; + this.msgQueue = new MessageQueue(kernel.getConfig()); - public abstract InetSocketAddress getInetSocketAddress(); + // register channel handlers + if (isInbound) { + pipe.addLast("inboundLimitHandler", + new ConnectionLimitHandler(kernel.getConfig().getNodeSpec().getNetMaxInboundConnectionsPerIp())); + } + pipe.addLast("readTimeoutHandler", new ReadTimeoutHandler(kernel.getConfig().getNodeSpec().getNetChannelIdleTimeout(), TimeUnit.MILLISECONDS)); + pipe.addLast("xdagFrameHandler", new XdagFrameHandler(kernel.getConfig())); + pipe.addLast("xdagMessageHandler", new XdagMessageHandler(kernel.getConfig())); + p2pHandler = new XdagP2pHandler(this, kernel); + pipe.addLast("xdagP2pHandler", p2pHandler); + } - public abstract boolean isActive(); + public void close() { + socket.close(); + } - public abstract void setActive(boolean b); + public MessageQueue getMessageQueue() { + return msgQueue; + } - public abstract Node getNode(); + public boolean isInbound() { + return isInbound; + } - public abstract void sendNewBlock(BlockWrapper blockWrapper); + public boolean isOutbound() { + return !isInbound(); + } - public abstract void onDisconnect(); + public boolean isActive() { + return isActive; + } - public abstract void dropConnection(); + public void setActive(Peer remotePeer) { + this.remotePeer = remotePeer; + this.isActive = true; + } - public abstract Xdag getXdag(); + public void setInactive() { + this.isActive = false; + } - public abstract boolean isDisconnected(); + public String getRemoteIp() { + return remoteAddress.getAddress().getHostAddress(); + } - public abstract MessageQueue getMessageQueue(); + public int getRemotePort() { + return remoteAddress.getPort(); + } - public abstract Kernel getKernel(); + @Override + public String toString() { + return "Channel [" + (isInbound ? "Inbound" : "Outbound") + ", remoteIp = " + getRemoteIp() + ", remotePeer = " + + remotePeer + "]"; + } } diff --git a/src/main/java/io/xdag/net/manager/XdagChannelManager.java b/src/main/java/io/xdag/net/ChannelManager.java similarity index 63% rename from src/main/java/io/xdag/net/manager/XdagChannelManager.java rename to src/main/java/io/xdag/net/ChannelManager.java index 6de958a93..dfa2ab2b5 100644 --- a/src/main/java/io/xdag/net/manager/XdagChannelManager.java +++ b/src/main/java/io/xdag/net/ChannelManager.java @@ -22,27 +22,30 @@ * THE SOFTWARE. */ -package io.xdag.net.manager; +package io.xdag.net; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import io.xdag.Kernel; import io.xdag.core.BlockWrapper; -import io.xdag.net.Channel; -import io.xdag.net.node.Node; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; + +import org.apache.commons.lang3.StringUtils; + +import io.xdag.net.node.Node; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @Slf4j -public class XdagChannelManager { +public class ChannelManager { private final Kernel kernel; /** @@ -61,7 +64,7 @@ public class XdagChannelManager { private final Cache channelLastConnect = Caffeine.newBuilder().maximumSize(LRU_CACHE_SIZE).build(); - public XdagChannelManager(Kernel kernel) { + public ChannelManager(Kernel kernel) { this.kernel = kernel; // Resending new blocks to network in loop this.blockDistributeThread = new Thread(this::newBlocksDistributeLoop, "NewSyncThreadBlocks"); @@ -72,24 +75,86 @@ public void start() { blockDistributeThread.start(); } + public boolean isAcceptable(InetSocketAddress address) { + //对于进来的连接,只判断ip,不判断port + if (!addressSet.isEmpty()) { + for (InetSocketAddress inetSocketAddress : addressSet) { + // 不连接自己 + if (!isSelfAddress(address)&&inetSocketAddress.getAddress().equals(address.getAddress())) { + return true; + } + } + } + return false; + } + + public boolean isActiveIP(String ip) { + for (Channel c : activeChannels.values()) { + if (c.getRemoteIp().equals(ip)) { + return true; + } + } + + return false; + } + + public boolean isActivePeer(String peerId) { + return activeChannels.containsKey(peerId); + } + + public int size() { + return channels.size(); + } + public void add(Channel ch) { - log.debug("xdag channel manager->Channel added: remoteAddress = {}", ch.getInetSocketAddress()); - channels.put(ch.getInetSocketAddress(), ch); -// channelLastConnect.put(ch.getInetSocketAddress(),System.currentTimeMillis()); + log.debug("xdag channel manager->Channel added: remoteAddress = {}:{}", ch.getRemoteIp(), ch.getRemotePort()); + channels.put(ch.getRemoteAddress(), ch); + } + + public void remove(Channel ch) { + log.debug("Channel removed: remoteAddress = {}:{}", ch.getRemoteIp(), ch.getRemotePort()); + + channels.remove(ch.getRemoteAddress()); + if (ch.isActive()) { + activeChannels.remove(ch.getRemotePeer().getPeerId()); + ch.setInactive(); + } + } + + public void closeBlacklistedChannels() { + for (Map.Entry entry : channels.entrySet()) { + Channel channel = entry.getValue(); + if (!isAcceptable(channel.getRemoteAddress())) { + remove(channel); + channel.close(); + } + } } - public void notifyDisconnect(Channel channel) { - log.debug("xdag channel manager-> node {}: notifies about disconnect", channel.getInetSocketAddress()); - remove(channel); - channel.onDisconnect(); + public void onChannelActive(Channel channel, Peer peer) { + channel.setActive(peer); + activeChannels.put(peer.getPeerId(), channel); + log.debug("activeChannel size:" + activeChannels.size()); + } + + public List getActivePeers() { + List list = new ArrayList<>(); + + for (Channel c : activeChannels.values()) { + list.add(c.getRemotePeer()); + } + + return list; } public Set getActiveAddresses() { Set set = new HashSet<>(); + for (Channel c : activeChannels.values()) { - Node p = c.getNode(); - set.add(new InetSocketAddress(p.getHost(), p.getPort())); + Peer p = c.getRemotePeer(); + set.add(new InetSocketAddress(p.getIp(), p.getPort())); } + return set; } @@ -97,6 +162,30 @@ public List getActiveChannels() { return new ArrayList<>(activeChannels.values()); } + public List getActiveChannels(List peerIds) { + List list = new ArrayList<>(); + + for (String peerId : peerIds) { + if (activeChannels.containsKey(peerId)) { + list.add(activeChannels.get(peerId)); + } + } + + return list; + } + + public List getIdleChannels() { + List list = new ArrayList<>(); + + for (Channel c : activeChannels.values()) { + if (c.getMessageQueue().isIdle()) { + list.add(c); + } + } + + return list; + } + /** * Processing new blocks received from other peers from queue */ @@ -121,66 +210,30 @@ private void newBlocksDistributeLoop() { // TODO:怎么发送 目前是发给除receive的节点 public void sendNewBlock(BlockWrapper blockWrapper) { - Node receive; - // 说明是自己产生的 - if (blockWrapper.getRemoteNode() == null - || blockWrapper.getRemoteNode().equals(kernel.getClient().getNode())) { - receive = kernel.getClient().getNode(); - } else { - Channel receiveChannel = activeChannels.get(blockWrapper.getRemoteNode().getHexId()); - receive = receiveChannel != null ? receiveChannel.getNode() : null; - } +// Node receive; +// Peer blockPeer = blockWrapper.getRemotePeer(); +// Node node = kernel.getClient().getNode(); +// // 说明是自己产生的 +// if (blockPeer == null || (StringUtils.equals(blockPeer.getIp(), node.getIp()) && blockPeer.getPort() == node.getPort())) { +// receive = node; +// } else { +// Channel channel = activeChannels.get(blockWrapper.getRemotePeer().getPeerId()); +// receive = channel != null ? new Node(channel.getRemoteIp(), channel.getRemotePort()) : null; +// } for (Channel channel : activeChannels.values()) { - if (receive != null && channel.getNode().getHexId().equals(receive.getHexId())) { - log.debug("not send to sender node"); - continue; - } - channel.sendNewBlock(blockWrapper); +// Peer remotePeer = channel.getRemotePeer(); +// if (StringUtils.equals(remotePeer.getIp(), receive.getIp()) && remotePeer.getPort() == receive.getPort()) { +// log.debug("not send to sender node"); +// continue; +// } + channel.getP2pHandler().sendNewBlock(blockWrapper.getBlock(), blockWrapper.getTtl()); } } - public void onChannelActive(Channel channel, Node node) { - channel.setActive(true); - activeChannels.put(node.getHexId(), channel); - channelLastConnect.put(node.getAddress(),System.currentTimeMillis()); // use node to get address(conclude hostname) - log.debug("activeChannel size:" + activeChannels.size()); - } - public void onNewForeignBlock(BlockWrapper blockWrapper) { newForeignBlocks.add(blockWrapper); } - public boolean containsNode(Node node) { - return activeChannels.containsKey(node.getHexId()); - } - - public int size() { - return channels.size(); - } - - public void remove(Channel ch) { - log.debug("Channel removed: remoteAddress = {}", ch.getInetSocketAddress()); - channels.remove(ch.getInetSocketAddress()); - if (ch.isActive()) { - activeChannels.remove(ch.getNode().getHexId()); - ch.setActive(false); - } - } - - public boolean isAcceptable(InetSocketAddress address) { - - //对于进来的连接,只判断ip,不判断port - if (addressSet.size() != 0) { - for (InetSocketAddress inetSocketAddress : addressSet) { - // 不连接自己 - if (!isSelfAddress(address)&&inetSocketAddress.getAddress().equals(address.getAddress())) { - return true; - } - } - } - return false; - } - private void initWhiteIPs() { addressSet.addAll(kernel.getConfig().getNodeSpec().getWhiteIPList()); } @@ -201,7 +254,7 @@ public void stop() { } // 关闭所有连接 for (Channel channel : activeChannels.values()) { - channel.dropConnection(); + channel.close(); } } } diff --git a/src/main/java/io/xdag/mine/handler/ConnectionLimitHandler.java b/src/main/java/io/xdag/net/ConnectionLimitHandler.java similarity index 99% rename from src/main/java/io/xdag/mine/handler/ConnectionLimitHandler.java rename to src/main/java/io/xdag/net/ConnectionLimitHandler.java index c6fb95960..e77751c07 100644 --- a/src/main/java/io/xdag/mine/handler/ConnectionLimitHandler.java +++ b/src/main/java/io/xdag/net/ConnectionLimitHandler.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package io.xdag.mine.handler; +package io.xdag.net; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; diff --git a/src/main/java/io/xdag/net/Frame.java b/src/main/java/io/xdag/net/Frame.java new file mode 100644 index 000000000..405e1433e --- /dev/null +++ b/src/main/java/io/xdag/net/Frame.java @@ -0,0 +1,109 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import io.netty.buffer.ByteBuf; +import lombok.Getter; +import lombok.Setter; + +/** + * Represent a network packet frame in the xdagj. Numbers are signed and in big-endian. + * + *
    + *
  • FRAME := HEADER (16 bytes) + BODY (variable length)
  • + *
  • HEADER := VERSION + COMPRESS_TYPE + PACKET_TYPE + PACKET_ID + PACKET_SIZE + BODY_SIZE
  • + *
  • BODY := BINARY_DATA
  • + *
+ */ +@Getter +@Setter +public class Frame { + + public static final int HEADER_SIZE = 16; + public static final short VERSION = 0; + public static final byte COMPRESS_NONE = 0; + public static final byte COMPRESS_SNAPPY = 1; + + protected final short version; /* version, 2 bytes */ + protected final byte compressType; /* compress type, 1 byte */ + protected final byte packetType; /* packet type, 1 byte */ + protected final int packetId; /* packet id, 4 bytes */ + protected final int packetSize; /* packet size, 4 bytes */ + protected final int bodySize; /* body size, 4 bytes */ + + protected byte[] body; + + public Frame(short version, byte compressType, byte packetType, int packetId, int packetSize, int bodySize, + byte[] body) { + this.version = version; + this.compressType = compressType; + this.packetType = packetType; + this.packetId = packetId; + this.packetSize = packetSize; + this.bodySize = bodySize; + + this.body = body; + } + + /** + * Returns whether the packet is chunked. + */ + public boolean isChunked() { + return bodySize != packetSize; + } + + /** + * Writes frame header into the buffer. + * + */ + public void writeHeader(ByteBuf buf) { + buf.writeShort(getVersion()); + buf.writeByte(getCompressType()); + buf.writeByte(getPacketType()); + buf.writeInt(getPacketId()); + buf.writeInt(getPacketSize()); + buf.writeInt(getBodySize()); + } + + /** + * Reads frame header from the given buffer. + */ + public static Frame readHeader(ByteBuf in) { + short version = in.readShort(); + byte compressType = in.readByte(); + byte packetType = in.readByte(); + int packetId = in.readInt(); + int packetSize = in.readInt(); + int bodySize = in.readInt(); + + return new Frame(version, compressType, packetType, packetId, packetSize, bodySize, null); + } + + @Override + public String toString() { + return "PacketFrame [version=" + version + ", compressType=" + compressType + ", packetType=" + packetType + + ", packetId=" + packetId + ", packetSize=" + packetSize + ", bodySize=" + bodySize + "]"; + } + +} diff --git a/src/main/java/io/xdag/net/message/NetDB.java b/src/main/java/io/xdag/net/NetDB.java similarity index 97% rename from src/main/java/io/xdag/net/message/NetDB.java rename to src/main/java/io/xdag/net/NetDB.java index c0ac80277..bd8f5999f 100644 --- a/src/main/java/io/xdag/net/message/NetDB.java +++ b/src/main/java/io/xdag/net/NetDB.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package io.xdag.net.message; +package io.xdag.net; import static io.xdag.utils.BytesUtils.isFullZero; @@ -36,8 +36,11 @@ import java.util.List; import java.util.Objects; import java.util.Set; + +import lombok.Getter; import lombok.extern.slf4j.Slf4j; +@Getter @Slf4j public class NetDB { @@ -110,9 +113,9 @@ public void addNewIP(byte[] address) { */ public Set getIPList() { Set res = Sets.newHashSet(); - if (ipList.size() != 0) { + if (!ipList.isEmpty()) { for (IP ip : ipList) { - res.add(new Node(ip.getIp(), ip.getPort())); + res.add(new Node(ip.getIp().getHostAddress(), ip.getPort())); } } return res; @@ -153,10 +156,6 @@ public int getSize() { return ipList.size(); } - public List getIpList() { - return ipList; - } - @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); diff --git a/src/main/java/io/xdag/net/manager/NetDBManager.java b/src/main/java/io/xdag/net/NetDBManager.java similarity index 98% rename from src/main/java/io/xdag/net/manager/NetDBManager.java rename to src/main/java/io/xdag/net/NetDBManager.java index 5c51187fc..00cd22700 100644 --- a/src/main/java/io/xdag/net/manager/NetDBManager.java +++ b/src/main/java/io/xdag/net/NetDBManager.java @@ -22,11 +22,10 @@ * THE SOFTWARE. */ -package io.xdag.net.manager; +package io.xdag.net; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; -import io.xdag.net.message.NetDB; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/io/xdag/net/Peer.java b/src/main/java/io/xdag/net/Peer.java new file mode 100644 index 000000000..3c8901d32 --- /dev/null +++ b/src/main/java/io/xdag/net/Peer.java @@ -0,0 +1,66 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import io.xdag.Network; +import lombok.Getter; + +@Getter +public class Peer { + + private final Network network; + private final short networkVersion; + private final String peerId; + private final String ip; + private final int port; + private final String clientId; + private final String[] capabilities; + private long latestBlockNumber; + private long latency; + + public Peer(Network network, short networkVersion, String peerId, String ip, int port, String clientId, + String[] capabilities, long latestBlockNumber) { + this.network = network; + this.ip = ip; + this.port = port; + this.peerId = peerId; + this.networkVersion = networkVersion; + this.clientId = clientId; + this.capabilities = capabilities; + this.latestBlockNumber = latestBlockNumber; + } + + public void setLatestBlockNumber(long number) { + this.latestBlockNumber = number; + } + + public void setLatency(long latency) { + this.latency = latency; + } + + @Override + public String toString() { + return getPeerId() + "@" + ip + ":" + port; + } +} \ No newline at end of file diff --git a/src/main/java/io/xdag/net/XdagClient.java b/src/main/java/io/xdag/net/PeerClient.java similarity index 77% rename from src/main/java/io/xdag/net/XdagClient.java rename to src/main/java/io/xdag/net/PeerClient.java index 30e9150b3..f275f115b 100644 --- a/src/main/java/io/xdag/net/XdagClient.java +++ b/src/main/java/io/xdag/net/PeerClient.java @@ -24,6 +24,9 @@ package io.xdag.net; +import static io.xdag.crypto.Keys.toBytesAddress; +import static io.xdag.utils.WalletUtils.toBase58; + import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; @@ -32,55 +35,57 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.xdag.config.Config; -import io.xdag.net.handler.XdagChannelInitializer; import io.xdag.net.node.Node; import java.net.InetSocketAddress; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ThreadFactory; + +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.hyperledger.besu.crypto.KeyPair; @Slf4j -public class XdagClient { +@Getter +@Setter +public class PeerClient { private static final ThreadFactory factory = new BasicThreadFactory.Builder() .namingPattern("XdagClient-thread-%d") .daemon(true) .build(); - private final EventLoopGroup workerGroup; + private final String ip; private final int port; + + @Getter + private final KeyPair coinbase; + + private final EventLoopGroup workerGroup; + private final Config config; - private final String ip; + private final Set whilelist; private Node node; - public XdagClient(Config config) { + public PeerClient(Config config, KeyPair coinbase) { this.config = config; this.ip = config.getNodeSpec().getNodeIp(); this.port = config.getNodeSpec().getNodePort(); + this.coinbase = coinbase; this.workerGroup = new NioEventLoopGroup(0, factory); this.whilelist = new HashSet<>(); initWhiteIPs(); -// log.debug("XdagClient nodeId {}", getNode().getHexId()); } - /** - * Connects to the node and returns only upon connection close - */ - public void connect(String host, int port, XdagChannelInitializer xdagChannelInitializer) { - try { - ChannelFuture f = connectAsync(host, port, xdagChannelInitializer); - f.sync(); - } catch (Exception e) { -// log.error("message:" + e.getMessage(), e); - } + public String getPeerId() { + return toBase58(toBytesAddress(coinbase)); } - public ChannelFuture connectAsync( - String host, int port, XdagChannelInitializer xdagChannelInitializer) { - if (!isAcceptable(new InetSocketAddress(host, port))) { + public ChannelFuture connect(Node remoteNode, XdagChannelInitializer xdagChannelInitializer) { + if (!isAcceptable(new InetSocketAddress(remoteNode.getIp(), remoteNode.getPort()))) { return null; } Bootstrap b = new Bootstrap(); @@ -89,8 +94,8 @@ public ChannelFuture connectAsync( b.option(ChannelOption.TCP_NODELAY, true); b.option(ChannelOption.SO_KEEPALIVE, true); b.option(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); - b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getPoolSpec().getConnectionTimeout()); - b.remoteAddress(host, port); + b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, config.getNodeSpec().getConnectionTimeout()); + b.remoteAddress(remoteNode.toAddress()); b.handler(xdagChannelInitializer); return b.connect(); } @@ -108,12 +113,8 @@ public Node getNode() { return node; } - // 判断远程服务器是否可以连接 白名单 public boolean isAcceptable(InetSocketAddress address) { - //TODO res = netDBManager.canAccept(address); - - // 默认空为允许所有连接 - if (whilelist.size() != 0) { + if (!whilelist.isEmpty()) { return whilelist.contains(address); } diff --git a/src/main/java/io/xdag/net/XdagServer.java b/src/main/java/io/xdag/net/PeerServer.java similarity index 95% rename from src/main/java/io/xdag/net/XdagServer.java rename to src/main/java/io/xdag/net/PeerServer.java index 944b353ab..1adc5a44d 100644 --- a/src/main/java/io/xdag/net/XdagServer.java +++ b/src/main/java/io/xdag/net/PeerServer.java @@ -35,20 +35,19 @@ import io.netty.handler.logging.LoggingHandler; import io.netty.util.NettyRuntime; import io.xdag.Kernel; -import io.xdag.net.handler.XdagChannelInitializer; import io.xdag.utils.NettyUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.SystemUtils; @Slf4j -public class XdagServer { - private Kernel kernel; +public class PeerServer { + private final Kernel kernel; private EventLoopGroup bossGroup; private EventLoopGroup workerGroup; private ChannelFuture channelFuture; private final int workerThreadPoolSize = NettyRuntime.availableProcessors() * 2; - public XdagServer(final Kernel kernel) { + public PeerServer(final Kernel kernel) { this.kernel = kernel; } @@ -75,7 +74,7 @@ public void start(String ip, int port) { b.childOption(ChannelOption.TCP_NODELAY, true); b.childOption(ChannelOption.SO_KEEPALIVE, true); b.childOption(ChannelOption.MESSAGE_SIZE_ESTIMATOR, DefaultMessageSizeEstimator.DEFAULT); - b.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, kernel.getConfig().getPoolSpec().getConnectionTimeout()); + b.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, kernel.getConfig().getNodeSpec().getConnectionTimeout()); b.handler(new LoggingHandler()); b.childHandler(new XdagChannelInitializer(kernel, true, null)); log.debug("Xdag Node start host:[{}:{}].", ip, port); diff --git a/src/main/java/io/xdag/net/XdagChannel.java b/src/main/java/io/xdag/net/XdagChannel.java deleted file mode 100644 index b43bd087f..000000000 --- a/src/main/java/io/xdag/net/XdagChannel.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPipeline; -import io.xdag.Kernel; -import io.xdag.core.BlockWrapper; -import io.xdag.mine.handler.ConnectionLimitHandler; -import io.xdag.net.handler.MessageCodes; -import io.xdag.net.handler.Xdag; -import io.xdag.net.handler.XdagAdapter; -import io.xdag.net.handler.XdagBlockHandler; -import io.xdag.net.handler.XdagHandler; -import io.xdag.net.handler.XdagHandlerFactory; -import io.xdag.net.handler.XdagHandlerFactoryImpl; -import io.xdag.net.handler.XdagHandshakeHandler; -import io.xdag.net.message.MessageFactory; -import io.xdag.net.message.MessageQueue; -import io.xdag.net.message.impl.Xdag03MessageFactory; -import io.xdag.net.node.Node; -import java.net.InetSocketAddress; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@EqualsAndHashCode(callSuper = true) -@Slf4j -@Getter -@Setter -public class XdagChannel extends Channel { - - /** - * 握手 密钥 - */ - private XdagHandshakeHandler handshakeHandler; - /** - * 信息编码处理 - */ - private MessageCodes messageCodec; - /** - * 处理区块 - */ - private XdagBlockHandler blockHandler; - /** - * 获取xdag03handler - */ - private Xdag xdag = new XdagAdapter(); - /** - * 用来创建xdag03handler处理message 实际的逻辑操作 - */ - private XdagHandlerFactory xdagHandlerFactory; - - // TODO:记录该连接发送错误消息的次数,一旦超过某个值将断开连接 - private int failTimes; - - public XdagChannel(io.netty.channel.socket.SocketChannel socketChannel) { - this.socketChannel = socketChannel; - } - - public void init( - ChannelPipeline pipeline, - Kernel kernel, - boolean isServer, - InetSocketAddress inetSocketAddress) { - this.kernel = kernel; - this.inetSocketAddress = inetSocketAddress; - this.handshakeHandler = new XdagHandshakeHandler(kernel, this); - handshakeHandler.setServer(isServer); - if (isServer) { - pipeline.addLast("inboundLimitHandler", new ConnectionLimitHandler(kernel.getConfig().getNodeSpec().getMaxInboundConnectionsPerIp())); - } - pipeline.addLast("handshakeHandler", handshakeHandler); - this.messageQueue = new MessageQueue(this); - this.messageCodec = new MessageCodes(); - this.blockHandler = new XdagBlockHandler(this); - this.xdagHandlerFactory = new XdagHandlerFactoryImpl(kernel, this); - } - - public void initWithNode(final String host, final int port) { - if (node == null) { - node = new Node(host, port); - } - log.debug("Initwith Node host:" + host + " port:" + port + " node:" + node.getHexId()); - } - - @Override - public InetSocketAddress getInetSocketAddress() { - return this.inetSocketAddress; - } - - @Override - public boolean isActive() { - return this.isActive; - } - - @Override - public void setActive(boolean b) { - this.isActive = b; - } - - @Override - public Node getNode() { - return this.node; - } - - @Override - public void onDisconnect() { - isDisconnected = true; - } - - @Override - public boolean isDisconnected() { - return isDisconnected; - } - - @Override - public MessageQueue getMessageQueue() { - return this.messageQueue; - } - - @Override - public Kernel getKernel() { - return this.kernel; - } - - public void sendPubkey(ChannelHandlerContext ctx) throws Exception { - ByteBuf buffer = ctx.alloc().buffer(1024); - buffer.writeBytes(kernel.getConfig().getNodeSpec().getXKeys().pub); - ctx.writeAndFlush(buffer).sync(); - node.getStat().Outbound.add(2); - } - - public void sendPassword(ChannelHandlerContext ctx) throws Exception { - ByteBuf buffer = ctx.alloc().buffer(512); - buffer.writeBytes(kernel.getConfig().getNodeSpec().getXKeys().sect0_encoded); - ctx.writeAndFlush(buffer).sync(); - node.getStat().Outbound.add(1); - } - - @Override - public void sendNewBlock(BlockWrapper blockWrapper) { - log.debug("send a block hash is {}", blockWrapper.getBlock().getHashLow().toHexString()); - log.debug("ttl:" + blockWrapper.getTtl()); - xdag.sendNewBlock(blockWrapper.getBlock(), blockWrapper.getTtl()); - } - - /** - * 激活xdaghandler - */ - public void activateXdag(ChannelHandlerContext ctx, XdagVersion version) { - XdagHandler handler = xdagHandlerFactory.create(version); - MessageFactory messageFactory = createXdagMessageFactory(version); - blockHandler.setMessageFactory(messageFactory); - ctx.pipeline().addLast("blockHandler", blockHandler); - ctx.pipeline().addLast("messageCodec", messageCodec); - // 注册进消息队列 用来收发消息 - handler.setMsgQueue(messageQueue); - ctx.pipeline().addLast("xdag", handler); - handler.setChannel(this); - xdag = handler; - handler.activate(); - } - - private MessageFactory createXdagMessageFactory(XdagVersion version) { - if (version == XdagVersion.V03) { - return new Xdag03MessageFactory(); - } - throw new IllegalArgumentException("Xdag" + version + " is not supported"); - } - - @Override - public String toString() { - String format = "new channel"; - if (node != null) { - format = String.format("%s:%s", node.getHost(), node.getPort()); - } - return format; - } - - @Override - public Xdag getXdag() { - return xdag; - } - - @Override - public void dropConnection() { - log.debug("Disconnect with node:{}",socketChannel.remoteAddress()); - xdag.dropConnection(); - } -} diff --git a/src/main/java/io/xdag/net/handler/XdagChannelInitializer.java b/src/main/java/io/xdag/net/XdagChannelInitializer.java similarity index 71% rename from src/main/java/io/xdag/net/handler/XdagChannelInitializer.java rename to src/main/java/io/xdag/net/XdagChannelInitializer.java index 6b32f4239..9920f5d32 100644 --- a/src/main/java/io/xdag/net/handler/XdagChannelInitializer.java +++ b/src/main/java/io/xdag/net/XdagChannelInitializer.java @@ -22,15 +22,13 @@ * THE SOFTWARE. */ -package io.xdag.net.handler; +package io.xdag.net; -import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.FixedRecvByteBufAllocator; import io.netty.channel.socket.SocketChannel; import io.xdag.Kernel; -import io.xdag.net.XdagChannel; -import io.xdag.net.manager.XdagChannelManager; import io.xdag.net.node.Node; import java.net.InetSocketAddress; import lombok.extern.slf4j.Slf4j; @@ -38,10 +36,10 @@ @Slf4j public class XdagChannelInitializer extends ChannelInitializer { + private final Kernel kernel; + private final ChannelManager channelMgr; private final Node remoteNode; - private final XdagChannelManager channelMgr; private final boolean isServer; - protected Kernel kernel; public XdagChannelInitializer(Kernel kernel, boolean isServer, Node remoteNode) { this.kernel = kernel; @@ -53,21 +51,28 @@ public XdagChannelInitializer(Kernel kernel, boolean isServer, Node remoteNode) @Override protected void initChannel(SocketChannel ch) { try { - // log.debug("new input channel"); InetSocketAddress address = isServer ? ch.remoteAddress() : remoteNode.getAddress(); + log.debug("New {} channel: remoteAddress = {}:{}", isServer ? "inbound" : "outbound", + address.getAddress().getHostAddress(), address.getPort()); - // 判断进来的是不是白名单上的节点 if (isServer && !channelMgr.isAcceptable(address)) { - log.debug("Disallowed inbound connection: {}", address.toString()); + log.debug("Disallowed inbound connection: {}", address); ch.disconnect(); return; } - XdagChannel channel = new XdagChannel(ch); - channel.init(ch.pipeline(), kernel, isServer, address); - ch.config().setOption(ChannelOption.TCP_NODELAY, true); + Channel channel = new Channel(ch); + channel.init(ch.pipeline(), isServer, address, kernel); channelMgr.add(channel); - ch.closeFuture().addListener((ChannelFutureListener) future -> channelMgr.notifyDisconnect(channel)); + int bufferSize = Frame.HEADER_SIZE + kernel.getConfig().getNodeSpec().getNetMaxFrameBodySize(); + ch.config().setRecvByteBufAllocator(new FixedRecvByteBufAllocator(bufferSize)); + ch.config().setOption(ChannelOption.SO_RCVBUF, bufferSize); + ch.config().setOption(ChannelOption.SO_BACKLOG, 1024); + ch.config().setOption(ChannelOption.TCP_NODELAY, true); + // notify disconnection to channel manager + ch.closeFuture().addListener(future -> { + channelMgr.remove(channel); + }); } catch (Exception e) { log.error("Unexpected error: [{}]", e.getMessage(), e); } diff --git a/src/main/java/io/xdag/net/XdagFrameHandler.java b/src/main/java/io/xdag/net/XdagFrameHandler.java new file mode 100644 index 000000000..022125926 --- /dev/null +++ b/src/main/java/io/xdag/net/XdagFrameHandler.java @@ -0,0 +1,105 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import java.io.IOException; +import java.util.List; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageCodec; +import io.xdag.config.Config; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class XdagFrameHandler extends ByteToMessageCodec { + + private final Config config; + + public XdagFrameHandler(Config config) { + this.config = config; + } + + @Override + protected void encode(ChannelHandlerContext ctx, Frame frame, ByteBuf out) throws Exception { + // check version + if (frame.getVersion() != Frame.VERSION) { + log.error("Invalid frame version: {}", frame.getVersion()); + return; + } + + // check body size + int bodySize = frame.getBodySize(); + if (bodySize < 0 || bodySize > config.getNodeSpec().getNetMaxFrameBodySize()) { + log.error("Invalid frame body size: {}", bodySize); + return; + } + + // create a buffer + ByteBuf buf = out.alloc().buffer(Frame.HEADER_SIZE + bodySize); + frame.writeHeader(buf); + buf.writeBytes(frame.getBody()); + + // NOTE: write() operation does not flush automatically + + // write to context + ctx.write(buf); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + if (in.readableBytes() < Frame.HEADER_SIZE) { + return; + } + + // read frame header + int readerIndex = in.readerIndex(); + Frame frame = Frame.readHeader(in); + + // check version + if (frame.getVersion() != Frame.VERSION) { + throw new IOException("Invalid frame version: " + frame.getVersion()); + } + + // check body size + int bodySize = frame.getBodySize(); + if (bodySize < 0 || bodySize > config.getNodeSpec().getNetMaxFrameBodySize()) { + throw new IOException("Invalid frame body size: " + bodySize); + } + + if (in.readableBytes() < bodySize) { + // reset reader index if not available + in.readerIndex(readerIndex); + } else { + // read body + byte[] body = new byte[bodySize]; + in.readBytes(body); + frame.setBody(body); + + // deliver + out.add(frame); + } + } + +} diff --git a/src/main/java/io/xdag/net/XdagMessageHandler.java b/src/main/java/io/xdag/net/XdagMessageHandler.java new file mode 100644 index 000000000..360e746ae --- /dev/null +++ b/src/main/java/io/xdag/net/XdagMessageHandler.java @@ -0,0 +1,180 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.lang3.tuple.Pair; +import org.xerial.snappy.Snappy; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; +import io.xdag.config.Config; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageException; +import io.xdag.net.message.MessageFactory; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class XdagMessageHandler extends MessageToMessageCodec { + private static final int MAX_PACKETS = 16; + + private static final byte COMPRESS_TYPE = Frame.COMPRESS_SNAPPY; + + private final Cache, AtomicInteger>> incompletePackets = Caffeine.newBuilder() + .maximumSize(MAX_PACKETS).build(); + + private final Config config; + + private final MessageFactory messageFactory; + private final AtomicInteger count; + + private final int netMaxPacketSize; + + public XdagMessageHandler(Config config) { + this.config = config; + this.netMaxPacketSize = config.getNodeSpec().getNetMaxPacketSize(); + this.messageFactory = new MessageFactory(); + this.count = new AtomicInteger(0); + } + + @Override + protected void encode(ChannelHandlerContext ctx, Message msg, List out) throws Exception { + byte[] data = msg.getBody(); + byte[] dataCompressed = data; + + switch (COMPRESS_TYPE) { + case Frame.COMPRESS_SNAPPY: + dataCompressed = Snappy.compress(data); + break; + case Frame.COMPRESS_NONE: + break; + default: + log.error("Unsupported compress type: " + COMPRESS_TYPE); + return; + } + + byte packetType = msg.getCode().toByte(); + int packetId = count.incrementAndGet(); + int packetSize = dataCompressed.length; + + if (data.length > netMaxPacketSize || dataCompressed.length > netMaxPacketSize) { + log.error("Invalid packet size, max = {}, actual = {}", netMaxPacketSize, packetSize); + return; + } + + int limit = config.getNodeSpec().getNetMaxFrameBodySize(); + int total = (dataCompressed.length - 1) / limit + 1; + for (int i = 0; i < total; i++) { + byte[] body = new byte[(i < total - 1) ? limit : dataCompressed.length % limit]; + System.arraycopy(dataCompressed, i * limit, body, 0, body.length); + + out.add(new Frame(Frame.VERSION, COMPRESS_TYPE, packetType, packetId, packetSize, body.length, body)); + } + } + + @Override + protected void decode(ChannelHandlerContext ctx, Frame frame, List out) throws Exception { + Message decodedMsg = null; + + if (frame.isChunked()) { + synchronized (incompletePackets) { + int packetId = frame.getPacketId(); + Pair, AtomicInteger> pair = incompletePackets.getIfPresent(packetId); + if (pair == null) { + int packetSize = frame.getPacketSize(); + if (packetSize < 0 || packetSize > netMaxPacketSize) { + // this will kill the connection + throw new IOException("Invalid packet size: " + packetSize); + } + + pair = Pair.of(new ArrayList<>(), new AtomicInteger(packetSize)); + incompletePackets.put(packetId, pair); + } + + pair.getLeft().add(frame); + int remaining = pair.getRight().addAndGet(-frame.getBodySize()); + if (remaining == 0) { + decodedMsg = decodeMessage(pair.getLeft()); + + // remove complete packets from cache + incompletePackets.invalidate(packetId); + } else if (remaining < 0) { + throw new IOException("Packet remaining size went to negative"); + } + } + } else { + decodedMsg = decodeMessage(Collections.singletonList(frame)); + } + + if (decodedMsg != null) { + out.add(decodedMsg); + } + } + + protected Message decodeMessage(List frames) throws MessageException { + if (frames == null || frames.isEmpty()) { + throw new MessageException("Frames can't be null or empty"); + } + Frame head = frames.get(0); + + byte packetType = head.getPacketType(); + int packetSize = head.getPacketSize(); + + byte[] data = new byte[packetSize]; + int pos = 0; + for (Frame frame : frames) { + System.arraycopy(frame.getBody(), 0, data, pos, frame.getBodySize()); + pos += frame.getBodySize(); + } + + switch (head.getCompressType()) { + case Frame.COMPRESS_SNAPPY: + try { + // check uncompressed length to avoid OOM vulnerability + int length = Snappy.uncompressedLength(data); + if (length > netMaxPacketSize) { + throw new MessageException("Uncompressed data length is too big: " + length); + } + data = Snappy.uncompress(data); + } catch (IOException e) { + throw new MessageException(e); + } + break; + case Frame.COMPRESS_NONE: + break; + default: + throw new MessageException("Unsupported compress type: " + head.getCompressType()); + } + + return messageFactory.create(packetType, data); + } +} diff --git a/src/main/java/io/xdag/net/XdagP2pHandler.java b/src/main/java/io/xdag/net/XdagP2pHandler.java new file mode 100644 index 000000000..65bec77be --- /dev/null +++ b/src/main/java/io/xdag/net/XdagP2pHandler.java @@ -0,0 +1,514 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.lang3.time.FastDateFormat; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.bytes.MutableBytes; +import org.apache.tuweni.bytes.MutableBytes32; + +import com.google.common.util.concurrent.SettableFuture; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.xdag.Kernel; +import io.xdag.Network; +import io.xdag.config.Config; +import io.xdag.config.spec.NodeSpec; +import io.xdag.consensus.SyncManager; +import io.xdag.core.Block; +import io.xdag.core.BlockWrapper; +import io.xdag.core.Blockchain; +import io.xdag.core.XdagStats; +import io.xdag.crypto.SecureRandomUtils; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageQueue; +import io.xdag.net.message.ReasonCode; +import io.xdag.net.message.consensus.BlockExtRequestMessage; +import io.xdag.net.message.consensus.BlockRequestMessage; +import io.xdag.net.message.consensus.BlocksReplyMessage; +import io.xdag.net.message.consensus.BlocksRequestMessage; +import io.xdag.net.message.consensus.NewBlockMessage; +import io.xdag.net.message.consensus.SumReplyMessage; +import io.xdag.net.message.consensus.SumRequestMessage; +import io.xdag.net.message.consensus.SyncBlockMessage; +import io.xdag.net.message.consensus.SyncBlockRequestMessage; +import io.xdag.net.message.consensus.XdagMessage; +import io.xdag.net.message.p2p.DisconnectMessage; +import io.xdag.net.message.p2p.HelloMessage; +import io.xdag.net.message.p2p.InitMessage; +import io.xdag.net.message.p2p.PingMessage; +import io.xdag.net.message.p2p.PongMessage; +import io.xdag.net.message.p2p.WorldMessage; +import io.xdag.net.node.NodeManager; +import io.xdag.utils.XdagTime; +import io.xdag.utils.exception.UnreachableException; +import lombok.extern.slf4j.Slf4j; + +/** + * Xdag P2P message handler + */ +@Slf4j +public class XdagP2pHandler extends SimpleChannelInboundHandler { + + private static final ScheduledExecutorService exec = Executors + .newSingleThreadScheduledExecutor(new ThreadFactory() { + private final AtomicInteger cnt = new AtomicInteger(0); + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "p2p-" + cnt.getAndIncrement()); + } + }); + + private final Channel channel; + + private final Kernel kernel; + private final Config config; + private final NodeSpec nodeSpec; + private final Blockchain chain; + private final ChannelManager channelMgr; + private final NodeManager nodeMgr; + private final PeerClient client; + private final SyncManager syncMgr; + + private final NetDBManager netdbMgr; + private final MessageQueue msgQueue; + + private final AtomicBoolean isHandshakeDone = new AtomicBoolean(false); + + private ScheduledFuture getNodes = null; + private ScheduledFuture pingPong = null; + + private byte[] secret = SecureRandomUtils.secureRandom().generateSeed(InitMessage.SECRET_LENGTH); + private long timestamp = System.currentTimeMillis(); + + public XdagP2pHandler(Channel channel, Kernel kernel) { + this.channel = channel; + this.kernel = kernel; + this.config = kernel.getConfig(); + this.nodeSpec = kernel.getConfig().getNodeSpec(); + + this.chain = kernel.getBlockchain(); + this.channelMgr = kernel.getChannelMgr(); + this.nodeMgr = kernel.getNodeMgr(); + this.client = kernel.getClient(); + + this.syncMgr = kernel.getSyncMgr(); + this.netdbMgr = kernel.getNetDBMgr(); + this.msgQueue = channel.getMessageQueue(); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + log.debug("P2P handler active, remoteIp = {}, remotePort = {}", channel.getRemoteIp(), channel.getRemotePort()); + + // activate message queue + msgQueue.activate(ctx); + + // disconnect if too many connections + if (channel.isInbound() && channelMgr.size() >= config.getNodeSpec().getNetMaxInboundConnections()) { + msgQueue.disconnect(ReasonCode.TOO_MANY_PEERS); + return; + } + + if (channel.isInbound()) { + msgQueue.sendMessage(new InitMessage(secret, timestamp)); + } + super.channelActive(ctx); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + log.debug("P2P handler inactive, remoteIp = {}", channel.getRemoteIp()); + + // deactivate the message queue + msgQueue.deactivate(); + + // stop scheduled workers + if (getNodes != null) { + getNodes.cancel(false); + getNodes = null; + } + + if (pingPong != null) { + pingPong.cancel(false); + pingPong = null; + } + + super.channelInactive(ctx); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + log.debug("Exception in P2P handler, remoteIp = {}, remotePort = {}", channel.getRemoteIp(), channel.getRemotePort(),cause); + + // close connection on exception + ctx.close(); + } + + @Override + public void channelRead0(final ChannelHandlerContext ctx, Message msg) { + log.trace("Received message: {}", msg); + + switch (msg.getCode()) { + /* p2p */ + case DISCONNECT -> onDisconnect(ctx, (DisconnectMessage) msg); + case PING -> onPing(); + case PONG -> onPong(); + case HANDSHAKE_INIT -> onHandshakeInit((InitMessage) msg); + case HANDSHAKE_HELLO -> onHandshakeHello((HelloMessage) msg); + case HANDSHAKE_WORLD -> onHandshakeWorld((WorldMessage) msg); + + /* sync */ + case BLOCKS_REQUEST, BLOCKS_REPLY, SUMS_REQUEST, SUMS_REPLY, BLOCKEXT_REQUEST, BLOCKEXT_REPLY, BLOCK_REQUEST, NEW_BLOCK, SYNC_BLOCK, SYNCBLOCK_REQUEST -> + onXdag(msg); + default -> ctx.fireChannelRead(msg); + } + } + + protected void onDisconnect(ChannelHandlerContext ctx, DisconnectMessage msg) { + ReasonCode reason = msg.getReason(); + log.info("Received a DISCONNECT message: reason = {}, remoteIP = {}", + reason, channel.getRemoteIp()); + + ctx.close(); + } + + protected void onHandshakeInit(InitMessage msg) { + // unexpected + if (channel.isInbound()) { + return; + } + + // check message + if (!msg.validate()) { + this.msgQueue.disconnect(ReasonCode.INVALID_HANDSHAKE); + return; + } + + // record the secret + this.secret = msg.getSecret(); + this.timestamp = msg.getTimestamp(); + + // send the HELLO message + this.msgQueue.sendMessage(new HelloMessage(nodeSpec.getNetwork(), nodeSpec.getNetworkVersion(), client.getPeerId(), + client.getPort(), config.getClientId(), config.getClientCapabilities().toArray(), + chain.getLatestMainBlockNumber(), + secret, client.getCoinbase())); + } + + protected void onHandshakeHello(HelloMessage msg) { + // unexpected + if (channel.isOutbound()) { + return; + } + Peer peer = msg.getPeer(channel.getRemoteIp()); + + // check peer + ReasonCode code = checkPeer(peer, true); + if (code != null) { + msgQueue.disconnect(code); + return; + } + + // check message + if (!Arrays.equals(secret, msg.getSecret()) || !msg.validate(config)) { + msgQueue.disconnect(ReasonCode.INVALID_HANDSHAKE); + return; + } + + // send the WORLD message + this.msgQueue.sendMessage(new WorldMessage(nodeSpec.getNetwork(), nodeSpec.getNetworkVersion(), client.getPeerId(), + client.getPort(), config.getClientId(), config.getClientCapabilities().toArray(), + chain.getLatestMainBlockNumber(), + secret, client.getCoinbase())); + + // handshake done + onHandshakeDone(peer); + } + + protected void onHandshakeWorld(WorldMessage msg) { + // unexpected + if (channel.isInbound()) { + return; + } + Peer peer = msg.getPeer(channel.getRemoteIp()); + + // check peer + ReasonCode code = checkPeer(peer, true); + if (code != null) { + msgQueue.disconnect(code); + return; + } + + // check message + if (!Arrays.equals(secret, msg.getSecret()) || !msg.validate(config)) { + msgQueue.disconnect(ReasonCode.INVALID_HANDSHAKE); + return; + } + + // handshake done + onHandshakeDone(peer); + } + + private long lastPing; + + protected void onPing() { + PongMessage pong = new PongMessage(); + msgQueue.sendMessage(pong); + lastPing = System.currentTimeMillis(); + } + + protected void onPong() { + if (lastPing > 0) { + long latency = System.currentTimeMillis() - lastPing; + channel.getRemotePeer().setLatency(latency); + } + } + + protected void onXdag(Message msg) { + if (!isHandshakeDone.get()) { + return; + } + + switch (msg.getCode()) { + case NEW_BLOCK -> processNewBlock((NewBlockMessage) msg); + case BLOCK_REQUEST -> processBlockRequest((BlockRequestMessage) msg); + case BLOCKS_REQUEST -> processBlocksRequest((BlocksRequestMessage) msg); + case BLOCKS_REPLY -> processBlocksReply((BlocksReplyMessage) msg); + case SUMS_REQUEST -> processSumsRequest((SumRequestMessage) msg); + case SUMS_REPLY -> processSumsReply((SumReplyMessage) msg); + case BLOCKEXT_REQUEST -> processBlockExtRequest((BlockExtRequestMessage) msg); + case SYNC_BLOCK -> processSyncBlock((SyncBlockMessage) msg); + case SYNCBLOCK_REQUEST -> processSyncBlockRequest((SyncBlockRequestMessage) msg); + default -> throw new UnreachableException(); + } + } + + /** + * Check whether the peer is valid to connect. + */ + private ReasonCode checkPeer(Peer peer, boolean newHandShake) { + // has to be same network + if (newHandShake && !nodeSpec.getNetwork().equals(peer.getNetwork())) { + return ReasonCode.BAD_NETWORK; + } + + // has to be compatible version + if (nodeSpec.getNetworkVersion() != peer.getNetworkVersion()) { + return ReasonCode.BAD_NETWORK_VERSION; + } + + // not connected + if (client.getPeerId().equals(peer.getPeerId()) || channelMgr.isActivePeer(peer.getPeerId())) { + return ReasonCode.DUPLICATED_PEER_ID; + } + + // validator can't share IP address + if (channelMgr.isActiveIP(channel.getRemoteIp()) // already connected + && nodeSpec.getNetwork() == Network.MAINNET) { // on main net + return ReasonCode.VALIDATOR_IP_LIMITED; + } + + return null; + } + + private void onHandshakeDone(Peer peer) { + if (isHandshakeDone.compareAndSet(false, true)) { + // register into channel manager + channelMgr.onChannelActive(channel, peer); + + // start ping pong + pingPong = exec.scheduleAtFixedRate(() -> msgQueue.sendMessage(new PingMessage()), + channel.isInbound() ? 1 : 0, 1, TimeUnit.MINUTES); + } else { + msgQueue.disconnect(ReasonCode.HANDSHAKE_EXISTS); + } + } + + /** + * ********************** Message Processing * *********************** + */ + protected void processNewBlock(NewBlockMessage msg) { + Block block = msg.getBlock(); + if (syncMgr.isSyncOld()) { + return; + } + + log.debug("processNewBlock:{} from node {}", block.getHashLow(), channel.getRemoteAddress()); + BlockWrapper bw = new BlockWrapper(block, msg.getTtl() - 1, channel.getRemotePeer(), false); + syncMgr.validateAndAddNewBlock(bw); + } + + protected void processSyncBlock(SyncBlockMessage msg) { + Block block = msg.getBlock(); + + log.debug("processSyncBlock:{} from node {}", block.getHashLow(), channel.getRemoteAddress()); + BlockWrapper bw = new BlockWrapper(block, msg.getTtl() - 1, channel.getRemotePeer(), true); + syncMgr.validateAndAddNewBlock(bw); + } + + /** + * 区块请求响应一个区块 并开启一个线程不断发送一段时间内的区块 * + */ + protected void processBlocksRequest(BlocksRequestMessage msg) { + // 更新全网状态 + updateXdagStats(msg); + long startTime = msg.getStarttime(); + long endTime = msg.getEndtime(); + long random = msg.getRandom(); + + // TODO: paulochen 处理多区块请求 + // // 如果大于快照点的话 我可以发送 + // if (startTime > 1658318225407L) { + // // TODO: 如果请求时间间隔过大,启动新线程发送,目的是避免攻击 + log.debug("Send blocks between {} and {} to node {}", + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(startTime)), + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(endTime)), + channel.getRemoteAddress()); + List blocks = chain.getBlocksByTime(startTime, endTime); + for (Block block : blocks) { + SyncBlockMessage blockMsg = new SyncBlockMessage(block, 1); + msgQueue.sendMessage(blockMsg); + } + msgQueue.sendMessage(new BlocksReplyMessage(startTime, endTime, random, chain.getXdagStats(), netdbMgr.getNetDB())); + } + + protected void processBlocksReply(BlocksReplyMessage msg) { + updateXdagStats(msg); + long randomSeq = msg.getRandom(); + SettableFuture sf = kernel.getSync().getBlocksRequestMap().get(randomSeq); + if (sf != null) { + sf.set(Bytes.wrap(new byte[]{0})); + } + } + + /** + * 将sumRequest的后8个字段填充为自己的sum 修改type类型为reply 发送 + */ + protected void processSumsRequest(SumRequestMessage msg) { + updateXdagStats(msg); + MutableBytes sums = MutableBytes.create(256); + // TODO: paulochen 处理sum请求 + kernel.getBlockStore().loadSum(msg.getStarttime(),msg.getEndtime(),sums); + SumReplyMessage reply = new SumReplyMessage(msg.getEndtime(), msg.getRandom(), + chain.getXdagStats(), sums, netdbMgr.getNetDB()); + msgQueue.sendMessage(reply); + } + + protected void processSumsReply(SumReplyMessage msg) { + updateXdagStats(msg); + long randomSeq = msg.getRandom(); + SettableFuture sf = kernel.getSync().getSumsRequestMap().get(randomSeq); + if (sf != null) { + sf.set(msg.getSum()); + } + } + + protected void processBlockExtRequest(BlockExtRequestMessage msg) { + } + + protected void processBlockRequest(BlockRequestMessage msg) { + Bytes hash = msg.getHash(); + Block block = chain.getBlockByHash(Bytes32.wrap(hash), true); + int ttl = config.getNodeSpec().getTTL(); + if (block != null) { + log.debug("processBlockRequest: findBlock" + Bytes32.wrap(hash).toHexString()); + NewBlockMessage message = new NewBlockMessage(block, ttl); + msgQueue.sendMessage(message); + } + } + + private void processSyncBlockRequest(SyncBlockRequestMessage msg) { + Bytes hash = msg.getHash(); + Block block = chain.getBlockByHash(Bytes32.wrap(hash), true); + if (block != null) { + log.debug("processSyncBlockRequest, findBlock: {}, to node: {}", Bytes32.wrap(hash).toHexString(), channel.getRemoteAddress()); + SyncBlockMessage message = new SyncBlockMessage(block, 1); + msgQueue.sendMessage(message); + } + } + + /** + * ********************** Xdag Message ************************ + */ + public void sendNewBlock(Block newBlock, int TTL) { + log.debug("send block:{} to node:{}", newBlock.getHashLow(), channel.getRemoteAddress()); + NewBlockMessage msg = new NewBlockMessage(newBlock, TTL); + sendMessage(msg); + } + + public long sendGetBlocks(long startTime, long endTime) { + log.debug("Request blocks between {} and {} from node {}", + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(startTime)), + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(endTime)), + channel.getRemoteAddress()); + BlocksRequestMessage msg = new BlocksRequestMessage(startTime, endTime, chain.getXdagStats(), + netdbMgr.getNetDB()); + sendMessage(msg); + return msg.getRandom(); + } + + public long sendGetBlock(MutableBytes32 hash, boolean isOld) { + XdagMessage msg; + // log.debug("sendGetBlock:[{}]", Hex.toHexString(hash)); + msg = isOld ? new SyncBlockRequestMessage(hash, kernel.getBlockchain().getXdagStats(), netdbMgr.getNetDB()) + : new BlockRequestMessage(hash, kernel.getBlockchain().getXdagStats(), netdbMgr.getNetDB()); + log.debug("Request block {} isold: {} from node {}", hash, isOld,channel.getRemoteAddress()); + sendMessage(msg); + return msg.getRandom(); + } + + public long sendGetSums(long startTime, long endTime) { + SumRequestMessage msg = new SumRequestMessage(startTime, endTime, chain.getXdagStats(), + netdbMgr.getNetDB()); + sendMessage(msg); + return msg.getRandom(); + } + + public void sendMessage(Message message) { + msgQueue.sendMessage(message); + } + + public void updateXdagStats(XdagMessage message) { + // Confirm that the remote stats has been updated, used to check local state. + syncMgr.getIsUpdateXdagStats().compareAndSet(false, true); + XdagStats remoteXdagStats = message.getXdagStats(); + chain.getXdagStats().update(remoteXdagStats); + netdbMgr.updateNetDB(message.getRemoteNetdb()); + } + +} diff --git a/src/main/java/io/xdag/net/XdagVersion.java b/src/main/java/io/xdag/net/XdagVersion.java deleted file mode 100644 index 563dbb40a..000000000 --- a/src/main/java/io/xdag/net/XdagVersion.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net; - -import java.util.List; - -import com.google.common.collect.Lists; - -public enum XdagVersion { - V03((byte) 3); - - public static final byte LOWER = V03.getCode(); - public static final byte UPPER = V03.getCode(); - - private final byte code; - - XdagVersion(byte code) { - this.code = code; - } - - public static XdagVersion fromCode(int code) { - for (XdagVersion v : values()) { - if (v.code == code) { - return v; - } - } - - return null; - } - - public static boolean isSupported(byte code) { - return code >= LOWER && code <= UPPER; - } - - public static List supported() { - List supported = Lists.newArrayList(); - for (XdagVersion v : values()) { - if (isSupported(v.code)) { - supported.add(v); - } - } - return supported; - } - - public byte getCode() { - return code; - } - -} diff --git a/src/main/java/io/xdag/net/handler/MessageCodes.java b/src/main/java/io/xdag/net/handler/MessageCodes.java deleted file mode 100644 index a42a3d112..000000000 --- a/src/main/java/io/xdag/net/handler/MessageCodes.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToMessageCodec; -import io.xdag.core.XdagBlock; -import io.xdag.net.message.Message; -import java.util.List; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; - -@EqualsAndHashCode(callSuper = false) -@Data -@Slf4j -public class MessageCodes extends MessageToMessageCodec { - - public MessageCodes() { - } - - public static XdagBlock convertMessage(Message message) { - return new XdagBlock(message.getEncoded().toArray()); - } - - /** - * 出去的第二道 - */ - @Override - protected void encode(ChannelHandlerContext ctx, Message msg, List out) { - XdagBlock xdagblock = convertMessage(msg); - out.add(xdagblock); - } - - /** - * 进来的第二道 - */ - @Override - protected void decode(ChannelHandlerContext ctx, Message msg, List out) { - out.add(msg); - } - - -} diff --git a/src/main/java/io/xdag/net/handler/Xdag03.java b/src/main/java/io/xdag/net/handler/Xdag03.java deleted file mode 100644 index f7d851ab6..000000000 --- a/src/main/java/io/xdag/net/handler/Xdag03.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import com.google.common.util.concurrent.SettableFuture; -import io.netty.channel.ChannelHandlerContext; -import io.xdag.Kernel; -import io.xdag.core.Block; -import io.xdag.core.BlockWrapper; -import io.xdag.core.XdagStats; -import io.xdag.net.Channel; -import io.xdag.net.XdagVersion; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.Message; -import io.xdag.net.message.impl.*; -import io.xdag.utils.XdagTime; -import java.util.List; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.time.FastDateFormat; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes; -import org.apache.tuweni.bytes.MutableBytes32; - -@EqualsAndHashCode(callSuper = true) -@Data -@Slf4j -public class Xdag03 extends XdagHandler { - - public Xdag03(Kernel kernel, Channel channel) { - this.kernel = kernel; - this.channel = channel; - this.blockchain = kernel.getBlockchain(); - this.syncMgr = kernel.getSyncMgr(); - this.version = XdagVersion.V03; - this.netDBManager = kernel.getNetDBMgr(); - } - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Message msg) { - switch (msg.getCommand()) { - case NEW_BLOCK -> processNewBlock((NewBlockMessage) msg); - case BLOCK_REQUEST -> processBlockRequest((BlockRequestMessage) msg); - case BLOCKS_REQUEST -> processBlocksRequest((BlocksRequestMessage) msg); - case BLOCKS_REPLY -> processBlocksReply((BlocksReplyMessage) msg); - case SUMS_REQUEST -> processSumsRequest((SumRequestMessage) msg); - case SUMS_REPLY -> processSumsReply((SumReplyMessage) msg); - case BLOCKEXT_REQUEST -> processBlockExtRequest((BlockExtRequestMessage) msg); - case SYNC_BLOCK -> processSyncBlock((SyncBlockMessage) msg); - case SYNCBLOCK_REQUEST -> processSyncBlockRequest((SyncBlockRequestMessage) msg); - default -> { - } - } - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) { - msgQueue.activate(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) { - log.debug("channelInactive:[{}] ", ctx.toString()); - killTimers(); - disconnect(); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - log.debug("exceptionCaught:[{}]", cause.getMessage(), cause); - ctx.close(); - killTimers(); - disconnect(); - } - - @Override - public void dropConnection() { - log.info("Peer {}: is a bad one, drop", channel.getNode().getAddress()); - disconnect(); - } - - public void killTimers() { - log.debug("msgQueue stop"); - msgQueue.close(); - } - - /** - * ********************** Message Processing * *********************** - */ - protected void processNewBlock(NewBlockMessage msg) { - Block block = msg.getBlock(); - if (syncMgr.isSyncOld()) { - return; - } - - log.debug("processNewBlock:{} from node {}", block.getHashLow(), channel.getInetSocketAddress()); - BlockWrapper bw = new BlockWrapper(block, msg.getTtl() - 1, channel.getNode(), false); - syncMgr.validateAndAddNewBlock(bw); - } - - protected void processSyncBlock(SyncBlockMessage msg) { - Block block = msg.getBlock(); - - log.debug("processSyncBlock:{} from node {}", block.getHashLow(), channel.getInetSocketAddress()); - BlockWrapper bw = new BlockWrapper(block, msg.getTtl() - 1, channel.getNode(), true); - syncMgr.validateAndAddNewBlock(bw); - } - - /** - * 区块请求响应一个区块 并开启一个线程不断发送一段时间内的区块 * - */ - protected void processBlocksRequest(BlocksRequestMessage msg) { - // 更新全网状态 - updateXdagStats(msg); - long startTime = msg.getStarttime(); - long endTime = msg.getEndtime(); - long random = msg.getRandom(); - - // TODO: paulochen 处理多区块请求 -// // 如果大于快照点的话 我可以发送 -// if (startTime > 1658318225407L) { -// // TODO: 如果请求时间间隔过大,启动新线程发送,目的是避免攻击 - log.debug("Send blocks between {} and {} to node {}", - FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(startTime)), - FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(endTime)), - channel.getInetSocketAddress()); - List blocks = blockchain.getBlocksByTime(startTime, endTime); - for (Block block : blocks) { - SyncBlockMessage blockMsg = new SyncBlockMessage(block, 1); - sendMessage(blockMsg); - } - sendMessage(new BlocksReplyMessage(startTime, endTime, random, kernel.getBlockchain().getXdagStats(), - netDBManager.getNetDB())); -// } - } - - protected void processBlocksReply(BlocksReplyMessage msg) { - updateXdagStats(msg); - long randomSeq = msg.getRandom(); - SettableFuture sf = kernel.getSync().getBlocksRequestMap().get(randomSeq); - if (sf != null) { - sf.set(Bytes.wrap(new byte[]{0})); - } - } - - /** - * 将sumRequest的后8个字段填充为自己的sum 修改type类型为reply 发送 - */ - protected void processSumsRequest(SumRequestMessage msg) { - updateXdagStats(msg); - MutableBytes sums = MutableBytes.create(256); - // TODO: paulochen 处理sum请求 - kernel.getBlockStore().loadSum(msg.getStarttime(),msg.getEndtime(),sums); - SumReplyMessage reply = new SumReplyMessage(msg.getEndtime(), msg.getRandom(), - kernel.getBlockchain().getXdagStats(), sums,netDBManager.getNetDB()); - sendMessage(reply); - } - - protected void processSumsReply(SumReplyMessage msg) { - updateXdagStats(msg); - long randomSeq = msg.getRandom(); - SettableFuture sf = kernel.getSync().getSumsRequestMap().get(randomSeq); - if (sf != null) { - sf.set(msg.getSum()); - } - } - - protected void processBlockExtRequest(BlockExtRequestMessage msg) { - } - - protected void processBlockRequest(BlockRequestMessage msg) { - Bytes32 hash = msg.getHash(); - MutableBytes32 find = MutableBytes32.create(); - find.set(8, hash.reverse().slice(8, 24)); - Block block = blockchain.getBlockByHash(find, true); - int ttl = kernel.getConfig().getNodeSpec().getTTL(); - if (block != null) { - log.debug("processBlockRequest: findBlock" + Bytes32.wrap(find).toHexString()); - NewBlockMessage message = new NewBlockMessage(block, ttl); - sendMessage(message); - } - } - - private void processSyncBlockRequest(SyncBlockRequestMessage msg) { - Bytes32 hash = msg.getHash(); - MutableBytes32 find = MutableBytes32.create(); - find.set(8, hash.reverse().slice(8, 24)); - Block block = blockchain.getBlockByHash(find, true); - if (block != null) { - log.debug("processSyncBlockRequest, findBlock: {}, to node: {}", Bytes32.wrap(find).toHexString(), channel.getInetSocketAddress()); - SyncBlockMessage message = new SyncBlockMessage(block, 1); - sendMessage(message); - } - } - - /** - * ********************** Message Sending * *********************** - */ - @Override - public void sendNewBlock(Block newBlock, int TTL) { - log.debug("send block:{} to node:{}", newBlock.getHashLow(), channel.getInetSocketAddress()); - NewBlockMessage msg = new NewBlockMessage(newBlock, TTL); - sendMessage(msg); - } - - @Override - public long sendGetBlocks(long startTime, long endTime) { - log.debug("Request blocks between {} and {} from node {}", - FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(startTime)), - FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS").format(XdagTime.xdagTimestampToMs(endTime)), - channel.getInetSocketAddress()); - BlocksRequestMessage msg = new BlocksRequestMessage(startTime, endTime, kernel.getBlockchain().getXdagStats(), - netDBManager.getNetDB()); - sendMessage(msg); - return msg.getRandom(); - } - - @Override - public long sendGetBlock(MutableBytes32 hash, boolean isOld) { - AbstractMessage msg; -// log.debug("sendGetBlock:[{}]", Hex.toHexString(hash)); - msg = isOld ? new SyncBlockRequestMessage(hash, kernel.getBlockchain().getXdagStats(), netDBManager.getNetDB()) - : new BlockRequestMessage(hash, kernel.getBlockchain().getXdagStats(), netDBManager.getNetDB()); - log.debug("Request block {} isold: {} from node {}", hash, isOld,channel.getInetSocketAddress()); - sendMessage(msg); - return msg.getRandom(); - } - - @Override - public long sendGetSums(long startTime, long endTime) { - SumRequestMessage msg = new SumRequestMessage(startTime, endTime, kernel.getBlockchain().getXdagStats(), - netDBManager.getNetDB()); - sendMessage(msg); - return msg.getRandom(); - } - - @Override - public void sendMessage(Message message) { - if (msgQueue.isRunning()) { - msgQueue.sendMessage(message); - } else { - log.debug("msgQueue is close"); - } - } - - protected void disconnect() { - msgQueue.disconnect(); - } - - @Override - public void activate() { - log.debug("Xdag protocol activate"); - //// xdagListener.trace("Xdag protocol activate"); - } - - public void updateXdagStats(AbstractMessage message) { - // Confirm that the remote stats has been updated, used to check local state. - syncMgr.getIsUpdateXdagStats().compareAndSet(false, true); - XdagStats remoteXdagStats = message.getXdagStats(); - kernel.getBlockchain().getXdagStats().update(remoteXdagStats); - kernel.getNetDBMgr().updateNetDB(message.getNetDB()); - } - -} diff --git a/src/main/java/io/xdag/net/handler/XdagAdapter.java b/src/main/java/io/xdag/net/handler/XdagAdapter.java deleted file mode 100644 index d8cf26c5a..000000000 --- a/src/main/java/io/xdag/net/handler/XdagAdapter.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import io.xdag.core.Block; -import io.xdag.net.XdagVersion; -import io.xdag.net.message.Message; -import org.apache.tuweni.bytes.MutableBytes32; - -public class XdagAdapter implements Xdag { - - @Override - public void sendNewBlock(Block newBlock, int ttl) { - // TODO Auto-generated method stub - } - - @Override - public long sendGetBlocks(long startTime, long endTime) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long sendGetBlock(MutableBytes32 hash, boolean isOld) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long sendGetSums(long startTime, long endTime) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void dropConnection() { - // TODO Auto-generated method stub - } - - @Override - public void activate() { - // TODO Auto-generated method stub - } - - @Override - public XdagVersion getVersion() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void sendMessage(Message message) { - // TODO Auto-generated method stub - } -} diff --git a/src/main/java/io/xdag/net/handler/XdagBlockHandler.java b/src/main/java/io/xdag/net/handler/XdagBlockHandler.java deleted file mode 100644 index 8d2caa12a..000000000 --- a/src/main/java/io/xdag/net/handler/XdagBlockHandler.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import static io.xdag.utils.BasicUtils.crc32Verify; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageCodec; -import io.xdag.core.XdagBlock; -import io.xdag.core.XdagField; -import io.xdag.net.Channel; -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageFactory; -import io.xdag.net.message.impl.NewBlockMessage; -import io.xdag.net.message.impl.SyncBlockMessage; -import io.xdag.utils.BytesUtils; -import java.nio.ByteOrder; -import java.util.List; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes; - -@EqualsAndHashCode(callSuper = false) -@Slf4j -@Data -public class XdagBlockHandler extends ByteToMessageCodec { - - private Channel channel; - private MessageFactory messageFactory; - - public XdagBlockHandler(Channel channel) { - this.channel = channel; - } - - public static byte getMsgCode(XdagBlock xdagblock, int n) { - Bytes data = xdagblock.getData(); - long type = data.getLong(8, ByteOrder.LITTLE_ENDIAN); - return (byte) (type >> (n << 2) & 0xf); - } - - @Override - protected void encode( - ChannelHandlerContext channelHandlerContext, XdagBlock xdagblock, ByteBuf out) { - byte[] unCryptData = xdagblock.getData().toArray(); - out.writeBytes(unCryptData); - channel.getNode().getStat().Outbound.add(); - } - - @Override - protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List out) { - if (in.readableBytes() >= XdagBlock.XDAG_BLOCK_SIZE) { - log.trace("Decoding packet (" + in.readableBytes() + " bytes)"); - byte[] unCryptData = new byte[512]; - in.readBytes(unCryptData); - channel.getNode().getStat().Inbound.add(); - - // TODO:process xdagblock transport header - int ttl = (int) ((BytesUtils.bytesToLong(unCryptData, 0, true) >> 8) & 0xff); - //Used to distinguish between newBlockMessage and syncBlockMessage. - boolean isOld = ((BytesUtils.bytesToLong(unCryptData, 0, true) >> 31) & 1) == 1; - if (isDataIllegal(unCryptData.clone())) { - log.debug("Receive error block!"); - return; - } - - System.arraycopy(BytesUtils.longToBytes(0, true), 0, unCryptData, 0, 8); - - XdagBlock xdagBlock = new XdagBlock(unCryptData); - byte first_field_type = getMsgCode(xdagBlock, 0); - Message msg = null; - // block message - XdagField.FieldType netType = channel.getKernel().getConfig().getXdagFieldHeader(); - if (netType.asByte() == first_field_type) { - msg = isOld ? new SyncBlockMessage(xdagBlock, ttl) : new NewBlockMessage(xdagBlock, ttl); - } - // other message - else if (XdagField.FieldType.XDAG_FIELD_NONCE.asByte() == first_field_type) { - msg = messageFactory.create(getMsgCode(xdagBlock, 1), xdagBlock.getData()); - } - if (msg != null) { - out.add(msg); - } else { - log.debug("receive unknown block first_field_type :" + first_field_type); - } - - } else { - log.debug("length less than " + XdagBlock.XDAG_BLOCK_SIZE + " bytes"); - } - } - - public boolean isDataIllegal(byte[] uncryptData) { - long transportHeader = BytesUtils.bytesToLong(uncryptData, 0, true); - // Read bits 17 to 31 to get the length, and the 32nd bit stores the isOld flag. - long dataLength = (transportHeader >> 16 & 0x7fff); - int crc = BytesUtils.bytesToInt(uncryptData, 4, true); - // clean transport header - System.arraycopy(BytesUtils.longToBytes(0, true), 0, uncryptData, 4, 4); - return (dataLength != 512 || !crc32Verify(uncryptData, crc)); - } - -} diff --git a/src/main/java/io/xdag/net/handler/XdagHandler.java b/src/main/java/io/xdag/net/handler/XdagHandler.java deleted file mode 100644 index 0f768b718..000000000 --- a/src/main/java/io/xdag/net/handler/XdagHandler.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.xdag.Kernel; -import io.xdag.consensus.SyncManager; -import io.xdag.core.Block; -import io.xdag.core.Blockchain; -import io.xdag.net.Channel; -import io.xdag.net.XdagVersion; -import io.xdag.net.manager.NetDBManager; -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageQueue; -import io.xdag.net.message.XdagMessageCodes; -import java.math.BigInteger; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; - -@EqualsAndHashCode(callSuper = false) -@Data -@Slf4j -public abstract class XdagHandler extends SimpleChannelInboundHandler implements Xdag { - - protected Kernel kernel; - protected Blockchain blockchain; - protected XdagVersion version; - protected Channel channel; - protected MessageQueue msgQueue; - protected Block bestKnownBlock; - protected BigInteger totalDifficulty; - protected SyncManager syncMgr; - - protected NetDBManager netDBManager; - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Message msg) { - if (XdagMessageCodes.inRange(msg.getCommand().asByte(), version)) { - log.trace("XdagHandler invoke: [{}]", msg.getCommand()); - } - } -} diff --git a/src/main/java/io/xdag/net/handler/XdagHandlerFactoryImpl.java b/src/main/java/io/xdag/net/handler/XdagHandlerFactoryImpl.java deleted file mode 100644 index 05c62f38d..000000000 --- a/src/main/java/io/xdag/net/handler/XdagHandlerFactoryImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import io.xdag.Kernel; -import io.xdag.net.XdagChannel; -import io.xdag.net.XdagVersion; - -public class XdagHandlerFactoryImpl implements XdagHandlerFactory { - - protected XdagChannel channel; - protected Kernel kernel; - - public XdagHandlerFactoryImpl(Kernel kernel, XdagChannel channel) { - this.kernel = kernel; - this.channel = channel; - } - - @Override - public XdagHandler create(XdagVersion version) { - if (version == XdagVersion.V03) { - return new Xdag03(kernel, channel); - } - throw new IllegalArgumentException("Xdag " + version + " is not supported"); - } -} diff --git a/src/main/java/io/xdag/net/handler/XdagHandshakeHandler.java b/src/main/java/io/xdag/net/handler/XdagHandshakeHandler.java deleted file mode 100644 index e03bf8d2f..000000000 --- a/src/main/java/io/xdag/net/handler/XdagHandshakeHandler.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.ByteToMessageDecoder; -import io.xdag.Kernel; -import io.xdag.net.XdagChannel; -import io.xdag.net.XdagVersion; -import java.net.InetSocketAddress; -import java.util.Arrays; -import java.util.List; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Hex; - -@Slf4j -public class XdagHandshakeHandler extends ByteToMessageDecoder { - - private final XdagChannel channel; - private final Kernel kernel; - private boolean isServer; - - public XdagHandshakeHandler(Kernel kernel, XdagChannel channel) { - this.kernel = kernel; - this.channel = channel; - } - - public void setServer(boolean isServer) { - this.isServer = isServer; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - channel.initWithNode( - // 连接到对方的channel 并将对方记录为node - remoteAddress.getAddress().getHostAddress(), remoteAddress.getPort()); - log.debug("connect with node:{}", remoteAddress); - // TODO:如果为服务器端 发送pubKey - if (isServer) { - channel.sendPubkey(ctx); - } - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - if (channel.getNode().getStat().Inbound.get() < 4) { - // 如果还未发送pubkey - if (channel.getNode().getStat().Inbound.get() < 1) { - byte[] remotePubKey = new byte[1024]; - try { - in.readBytes(remotePubKey); - } catch (Exception e) { - return; - } - // 发送过pubkey后加2 - channel.getNode().getStat().Inbound.add(2); - if (!checkDnetPubkey(remotePubKey)) { - log.debug("illegal address from node:{}",channel.getInetSocketAddress().toString()); - return; - } - // 发送pubkey - if (isServer) { - // 如果已经发送了pubkey - if (channel.getNode().getStat().Outbound.get() == 2) { - channel.sendPassword(ctx); - } - } else { - channel.sendPubkey(ctx); - } - // 如果已经接收过pubkey - } else if (channel.getNode().getStat().Inbound.get() >= 1) { - // 读取set0 - byte[] word = new byte[512]; - in.readBytes(word); - channel.getNode().getStat().Inbound.add(); - if (!isServer) { - // 如果已经发送了pubkey - if (channel.getNode().getStat().Outbound.get() == 2) { - channel.sendPassword(ctx); - } - } - if (channel.getNode().getStat().Inbound.get() >= 3) { - - log.info("connect a new pool with node:{}", channel.getInetSocketAddress().toString()); - - // handshake ok - kernel.getChannelMgr().onChannelActive(channel, channel.getNode()); - ctx.pipeline().remove(this); - channel.activateXdag(ctx, XdagVersion.V03); - - // test connect whether send an address - byte[] remoteAddress = new byte[512]; - if (in.isReadable() && in.readableBytes() == 512) { - log.debug("hava address blocks need to send to:{}",Hex.encodeHexString(remoteAddress)); - in.readBytes(remoteAddress); - } - } - } - - } else { - byte[] uncryptData = new byte[512]; - in.readBytes(uncryptData); - log.debug("in=" + channel.getNode().getStat().Inbound.get() + ", receive block:" + Hex.encodeHexString(uncryptData)); - channel.getNode().getStat().Inbound.add(); - } - } - - public boolean checkDnetPubkey(byte[] pubkey) { - return Arrays.equals(kernel.getConfig().getNodeSpec().getXKeys().pub, pubkey); - } -} diff --git a/src/main/java/io/xdag/net/libp2p/Libp2pChannel.java b/src/main/java/io/xdag/net/libp2p/Libp2pChannel.java deleted file mode 100755 index 3deeff24f..000000000 --- a/src/main/java/io/xdag/net/libp2p/Libp2pChannel.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import io.libp2p.core.Connection; -import io.libp2p.core.multiformats.Multiaddr; -import io.libp2p.core.multiformats.Protocol; -import io.xdag.Kernel; -import io.xdag.core.BlockWrapper; -import io.xdag.net.Channel; -import io.xdag.net.handler.Xdag; -import io.xdag.net.message.MessageQueue; -import io.xdag.net.node.Node; -import java.net.InetSocketAddress; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.math.NumberUtils; - -/** - * @author wawa - */ -@Slf4j -@Getter -public class Libp2pChannel extends Channel { - - private final Connection connection; - private final Libp2pXdagProtocol protocol; - - public Libp2pChannel(Connection connection, Libp2pXdagProtocol protocol, Kernel kernel) { - this.connection = connection; - this.protocol = protocol; - this.kernel = kernel; - - Multiaddr multiaddr = connection.remoteAddress(); - String ip = Protocol.IP4.bytesToAddress(multiaddr.getFirstComponent(Protocol.IP4).getValue()); - String port = Protocol.TCP.bytesToAddress(multiaddr.getFirstComponent(Protocol.TCP).getValue()); - this.inetSocketAddress = new InetSocketAddress(ip, NumberUtils.toInt(port)); - this.node = new Node(connection.secureSession().getRemoteId().getBytes(), ip, NumberUtils.toInt(port)); - this.messageQueue = new MessageQueue(this); - log.debug("Initwith Node host:" + ip + " port:" + port + " node:" + node.getHexId()); - } - - @Override - public void sendNewBlock(BlockWrapper blockWrapper) { - protocol.getLibp2PXdagController().sendNewBlock(blockWrapper.getBlock(), blockWrapper.getTtl()); - } - - @Override - public void onDisconnect() { - isDisconnected = true; - } - - @Override - public boolean isDisconnected() { - return isDisconnected; - } - - @Override - public MessageQueue getMessageQueue() { - return messageQueue; - } - - @Override - public Kernel getKernel() { - return kernel; - } - - @Override - public InetSocketAddress getInetSocketAddress() { - return inetSocketAddress; - } - - @Override - public boolean isActive() { - return isActive; - } - - @Override - public void setActive(boolean b) { - isActive = b; - } - - @Override - public Node getNode() { - return node; - } - - @Override - public void dropConnection() { - connection.close(); - } - - @Override - public Xdag getXdag() { - return protocol.getLibp2PXdagController(); - } -} diff --git a/src/main/java/io/xdag/net/libp2p/Libp2pNetwork.java b/src/main/java/io/xdag/net/libp2p/Libp2pNetwork.java deleted file mode 100755 index ba853853e..000000000 --- a/src/main/java/io/xdag/net/libp2p/Libp2pNetwork.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import io.libp2p.core.Host; -import io.libp2p.core.PeerId; -import io.libp2p.core.crypto.PrivKey; -import io.libp2p.core.dsl.Builder; -import io.libp2p.core.dsl.BuilderJKt; -import io.libp2p.core.multiformats.Multiaddr; -import io.libp2p.core.multistream.ProtocolBinding; -import io.libp2p.core.mux.StreamMuxerProtocol; -import io.libp2p.crypto.keys.Secp256k1Kt; -import io.libp2p.security.noise.NoiseXXSecureChannel; -import io.libp2p.transport.tcp.TcpTransport; -import io.xdag.Kernel; -import io.xdag.net.libp2p.discovery.DiscV5Service; -import io.xdag.net.libp2p.peer.NodeId; -import io.xdag.utils.SafeFuture; -import java.net.InetSocketAddress; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes; -import org.hyperledger.besu.crypto.KeyPair; - -import com.google.common.collect.Lists; - -@Slf4j -@Getter -public class Libp2pNetwork { - - private final ProtocolBinding protocol; - private final PrivKey privKey; - private final AtomicReference state = new AtomicReference<>(State.IDLE); - private final Multiaddr advertisedAddr; - private final List bootnodes; - private int port; - private Host host; - private NodeId nodeId; - private String ip; - private DiscV5Service discV5Service; - public Libp2pNetwork(PrivKey privKey, Multiaddr listenAddr) { - this.protocol = new NonProtocol(); - this.privKey = privKey; - this.advertisedAddr = listenAddr; - this.bootnodes = Lists.newArrayList(); - } - - public Libp2pNetwork(Kernel kernel) { - this.port = kernel.getConfig().getNodeSpec().getLibp2pPort(); - this.protocol = new Libp2pXdagProtocol(kernel); - // libp2p use wallet default key - KeyPair key = kernel.getWallet().getDefKey(); - privKey = Secp256k1Kt.unmarshalSecp256k1PrivateKey(key.getPrivateKey().getEncoded()); - ip = kernel.getConfig().getNodeSpec().getNodeIp(); - nodeId = new LibP2PNodeId(PeerId.fromPubKey(privKey.publicKey())); - advertisedAddr = Libp2pUtils.fromInetSocketAddress( - new InetSocketAddress(kernel.getConfig().getNodeSpec().getNodeIp(), port), nodeId); - bootnodes = kernel.getConfig().getNodeSpec().getBootnodes(); - - } - - private void crate() { - host = BuilderJKt.hostJ(Builder.Defaults.None, - b -> { - b.getIdentity().setFactory(() -> privKey); - b.getTransports().add(TcpTransport::new); - b.getSecureChannels().add(NoiseXXSecureChannel::new); - b.getMuxers().add(StreamMuxerProtocol.getMplex()); - b.getNetwork().listen(advertisedAddr.toString()); - b.getProtocols().add(protocol); -// b.getDebug().getBeforeSecureHandler().setLogger(LogLevel.DEBUG, "wire.ciphered"); -// Firewall firewall = new Firewall(Duration.ofSeconds(100)); -// b.getDebug().getBeforeSecureHandler().addNettyHandler(firewall); -// b.getDebug().getMuxFramesHandler().setLogger(LogLevel.DEBUG, "wire.mux"); - }); - discV5Service = DiscV5Service.create(Bytes.wrap(privKey.raw()), ip, port, bootnodes); - } - - public SafeFuture start() { - if (!state.compareAndSet(State.IDLE, State.RUNNING)) { - return SafeFuture.failedFuture(new IllegalStateException("Network already started")); - } - crate(); - //16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj - log.info("id ={}", host.getPeerId()); - log.info("Starting libp2p network..."); - if (discV5Service != null) { - discV5Service.start(); - discV5Service.searchForPeers(); - } - return SafeFuture.of(host.start()) - .thenApply( - i -> { - log.debug(getNodeAddress()); - return null; - }); - } - - public void dail(String peer) { - Multiaddr address = Multiaddr.fromString(peer); - protocol.dial(host, address); - } - - public String getNodeAddress() { - return advertisedAddr.toString(); - } - - public DiscV5Service getDiscV5Service() { - return discV5Service; - } - - public SafeFuture stop() { - if (!state.compareAndSet(State.RUNNING, State.STOPPED)) { - return SafeFuture.COMPLETE; - } - log.debug("LibP2PNetwork.stop()"); - SafeFuture.of(discV5Service.stop()); - return SafeFuture.of(host.stop()); - } - - enum State { - IDLE, - RUNNING, - STOPPED - } - -} diff --git a/src/main/java/io/xdag/net/libp2p/Libp2pUtils.java b/src/main/java/io/xdag/net/libp2p/Libp2pUtils.java deleted file mode 100644 index 2b84bd786..000000000 --- a/src/main/java/io/xdag/net/libp2p/Libp2pUtils.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import static io.libp2p.crypto.keys.Secp256k1Kt.unmarshalSecp256k1PublicKey; - -import io.libp2p.core.PeerId; -import io.libp2p.core.crypto.PubKey; -import io.libp2p.core.multiformats.Multiaddr; -import io.xdag.net.libp2p.discovery.DiscoveryPeer; -import io.xdag.net.libp2p.peer.NodeId; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Optional; -import org.apache.tuweni.bytes.Bytes; -import org.ethereum.beacon.discovery.schema.EnrField; -import org.ethereum.beacon.discovery.schema.NodeRecord; - -/** - * @author wawa - */ -public class Libp2pUtils { - - public static Optional convertToDiscoveryPeer(final NodeRecord nodeRecord) { - return nodeRecord - .getTcpAddress() - .map(address -> socketAddressToDiscoveryPeer(nodeRecord, address)); - } - - public static DiscoveryPeer socketAddressToDiscoveryPeer( - final NodeRecord nodeRecord, final InetSocketAddress address) { - return new DiscoveryPeer(((Bytes) nodeRecord.get(EnrField.PKEY_SECP256K1)), address); - } - - public static String discoveryPeerToDailId(DiscoveryPeer peer) { - String dailId = fromInetSocketAddress(peer.getNodeAddress(), getNodeId(peer)).toString(); - return dailId.replaceAll("p2p", "ipfs"); - } - - public static Multiaddr fromInetSocketAddress( - final InetSocketAddress address, final NodeId nodeId) { - return addPeerId(fromInetSocketAddress(address, "tcp"), nodeId); - } - - public static LibP2PNodeId getNodeId(final DiscoveryPeer peer) { - final PubKey pubKey = unmarshalSecp256k1PublicKey(peer.getPublicKey().toArrayUnsafe()); - return new LibP2PNodeId(PeerId.fromPubKey(pubKey)); - } - - public static Multiaddr fromInetSocketAddress(final InetSocketAddress address, final String protocol) { - final String addrString = - String.format( - "/%s/%s/%s/%d", - protocol(address.getAddress()), - address.getAddress().getHostAddress(), - protocol, - address.getPort()); - return Multiaddr.fromString(addrString); - } - - public static String protocol(final InetAddress address) { - return address instanceof Inet6Address ? "ip6" : "ip4"; - } - - public static Multiaddr addPeerId(final Multiaddr addr, final NodeId nodeId) { -// return new Multiaddr(addr, Multiaddr.fromString("/p2p/" + nodeId.toBase58())); - return addr.withP2P(PeerId.fromBase58(nodeId.toBase58())); - } - - -} diff --git a/src/main/java/io/xdag/net/libp2p/Libp2pXdagProtocol.java b/src/main/java/io/xdag/net/libp2p/Libp2pXdagProtocol.java deleted file mode 100644 index 6c5554de1..000000000 --- a/src/main/java/io/xdag/net/libp2p/Libp2pXdagProtocol.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import io.libp2p.core.Connection; -import io.libp2p.core.P2PChannel; -import io.libp2p.core.multistream.ProtocolBinding; -import io.libp2p.core.multistream.ProtocolDescriptor; -import io.netty.channel.ChannelHandlerContext; -import io.xdag.Kernel; -import io.xdag.core.XdagStats; -import io.xdag.net.Channel; -import io.xdag.net.handler.MessageCodes; -import io.xdag.net.handler.Xdag03; -import io.xdag.net.handler.XdagBlockHandler; -import io.xdag.net.manager.XdagChannelManager; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.impl.Xdag03MessageFactory; -import java.util.concurrent.CompletableFuture; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Getter -@Setter -public class Libp2pXdagProtocol implements ProtocolBinding { - - private Kernel kernel; - private Libp2pChannel libp2pChannel; - private Libp2pXdagController libp2PXdagController; - private XdagBlockHandler blockHandler; - private XdagChannelManager channelManager; - - public Libp2pXdagProtocol(Kernel kernel) { - this.kernel = kernel; - this.channelManager = kernel.getChannelMgr(); - } - - - @Override - public ProtocolDescriptor getProtocolDescriptor() { - return new ProtocolDescriptor("xdagj-libp2p-protocol"); - } - - - @Override - public CompletableFuture initChannel(P2PChannel p2PChannel, String s) { - final Connection connection = ((io.libp2p.core.Stream) p2PChannel).getConnection(); - libp2pChannel = new Libp2pChannel(connection, this, kernel); - channelManager.add(libp2pChannel); - blockHandler = new XdagBlockHandler(libp2pChannel); - blockHandler.setMessageFactory(new Xdag03MessageFactory()); - channelManager.onChannelActive(libp2pChannel, libp2pChannel.getNode()); - MessageCodes messageCodes = new MessageCodes(); - libp2PXdagController = new Libp2pXdagController(kernel, libp2pChannel); - - // add handler - p2PChannel.pushHandler(blockHandler); - p2PChannel.pushHandler(messageCodes); - p2PChannel.pushHandler(libp2PXdagController); - - return libp2PXdagController.activeFuture; - } - - public static class Libp2pXdagController extends Xdag03 { - - CompletableFuture activeFuture; - XdagChannelManager channelManager; - - public Libp2pXdagController(Kernel kernel, Channel channel) { - super(kernel, channel); - channelManager = kernel.getChannelMgr(); - msgQueue = channel.getMessageQueue(); - activeFuture = new CompletableFuture<>(); - } - - @Override - public void channelActive(ChannelHandlerContext ctx) { - activeFuture.complete(this); - } - - //libp2p节点不自动连接dnet - @Override - public void updateXdagStats(AbstractMessage message) { - XdagStats remoteXdagStats = message.getXdagStats(); - kernel.getBlockchain().getXdagStats().update(remoteXdagStats); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) { - log.debug("channelInactive:[{}] ", ctx.toString()); - killTimers(); - disconnect(); - channelManager.remove(channel); - } - } - -} diff --git a/src/main/java/io/xdag/net/libp2p/NonProtocol.java b/src/main/java/io/xdag/net/libp2p/NonProtocol.java deleted file mode 100644 index f82f76722..000000000 --- a/src/main/java/io/xdag/net/libp2p/NonProtocol.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import io.libp2p.core.Connection; -import io.libp2p.core.P2PChannel; -import io.libp2p.core.Stream; -import io.libp2p.core.multistream.ProtocolBinding; -import io.libp2p.core.multistream.ProtocolDescriptor; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.SimpleChannelInboundHandler; -import io.netty.util.CharsetUtil; -import io.xdag.net.libp2p.peer.NodeId; -import java.util.concurrent.CompletableFuture; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class NonProtocol implements ProtocolBinding { - - private Connection connection; - - public NonProtocol() { - } - - @Override - public ProtocolDescriptor getProtocolDescriptor() { - return new ProtocolDescriptor("xdagj-non-protocol"); - } - - - @Override - public CompletableFuture initChannel(P2PChannel p2PChannel, String s) { - this.connection = ((Stream) p2PChannel).getConnection(); - final NodeId nodeId = new LibP2PNodeId(connection.secureSession().getRemoteId()); - Controller controller = new Controller(nodeId, p2PChannel); - p2PChannel.pushHandler(controller); - return controller.activeFuture; - } - - - /** - * SimpleChannelInboundHandler<> 括号是接受的对象 - */ - static class Controller extends SimpleChannelInboundHandler { - - protected final CompletableFuture activeFuture = new CompletableFuture<>(); - final NodeId nodeid; - public P2PChannel p2pChannel; - - public Controller(NodeId nodeid, P2PChannel p2pChannel) { - this.nodeid = nodeid; - this.p2pChannel = p2pChannel; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) { - String msg = "A message"; - byte[] bytes = msg.getBytes(CharsetUtil.UTF_8); - ByteBuf buf = Unpooled.wrappedBuffer(bytes); - ctx.writeAndFlush(buf); - activeFuture.complete(this); - } - - - //ByteBuf 是接受的对象 - @Override - protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf buf) { -// String s = buf.toString(CharsetUtil.UTF_8); -// System.out.println(s); - } - - } -} diff --git a/src/main/java/io/xdag/net/libp2p/discovery/DiscV5Service.java b/src/main/java/io/xdag/net/libp2p/discovery/DiscV5Service.java deleted file mode 100644 index 88faea3c0..000000000 --- a/src/main/java/io/xdag/net/libp2p/discovery/DiscV5Service.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p.discovery; - -import io.xdag.net.libp2p.Libp2pUtils; -import io.xdag.utils.SafeFuture; -import io.xdag.utils.Service; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; -import org.apache.tuweni.bytes.Bytes; -import org.ethereum.beacon.discovery.DiscoverySystem; -import org.ethereum.beacon.discovery.DiscoverySystemBuilder; -import org.ethereum.beacon.discovery.schema.NodeRecord; -import org.ethereum.beacon.discovery.schema.NodeRecordBuilder; - -/** - * @author wawa - */ -public class DiscV5Service extends Service { - - private final DiscoverySystem discoverySystem; - - public DiscV5Service(final DiscoverySystem discoverySystem) { - this.discoverySystem = discoverySystem; - } - - public static DiscV5Service create( - final Bytes privateKey, final String address, final int port, final List bootnodes) { - final DiscoverySystem discoveryManager = - new DiscoverySystemBuilder() - .privateKey(privateKey) - .bootnodes(bootnodes.toArray(new String[0])) - .localNodeRecord( - new NodeRecordBuilder().privateKey(privateKey).address(address, port).build()) - .build(); - - return new DiscV5Service(discoveryManager); - } - - @Override - protected SafeFuture doStart() { - return SafeFuture.of(discoverySystem.start()); - } - - @Override - protected SafeFuture doStop() { - discoverySystem.stop(); - return SafeFuture.completedFuture(null); - } - - public Stream streamKnownPeers() { - return activeNodes().map(Libp2pUtils::convertToDiscoveryPeer).flatMap(Optional::stream); - } - - public SafeFuture> searchForPeers() { - return SafeFuture.of(discoverySystem.searchForNewPeers()); - } - - public Optional getEnr() { - return Optional.of(discoverySystem.getLocalNodeRecord().asEnr()); - } - - private Stream activeNodes() { - return discoverySystem.streamLiveNodes(); - } -} diff --git a/src/main/java/io/xdag/net/libp2p/discovery/DiscoveryPeer.java b/src/main/java/io/xdag/net/libp2p/discovery/DiscoveryPeer.java deleted file mode 100644 index 1a38235d4..000000000 --- a/src/main/java/io/xdag/net/libp2p/discovery/DiscoveryPeer.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p.discovery; - -import com.google.common.base.MoreObjects; -import java.net.InetSocketAddress; -import java.util.Objects; -import lombok.Getter; -import org.apache.tuweni.bytes.Bytes; - -/** - * @author wawa - */ -@Getter -public class DiscoveryPeer { - - private final Bytes publicKey; - private final InetSocketAddress nodeAddress; - - public DiscoveryPeer(Bytes publicKey, InetSocketAddress nodeAddress) { - this.publicKey = publicKey; - this.nodeAddress = nodeAddress; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DiscoveryPeer that = (DiscoveryPeer) o; - return Objects.equals(publicKey, that.publicKey) && Objects.equals(nodeAddress, that.nodeAddress); - } - - @Override - public int hashCode() { - return Objects.hash(publicKey, nodeAddress); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("publicKey", publicKey) - .add("nodeAddress", nodeAddress) - .toString(); - } -} diff --git a/src/main/java/io/xdag/net/message/AbstractMessage.java b/src/main/java/io/xdag/net/message/AbstractMessage.java deleted file mode 100644 index 12b420550..000000000 --- a/src/main/java/io/xdag/net/message/AbstractMessage.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message; - -import static io.xdag.config.Constants.DNET_PKT_XDAG; -import static io.xdag.core.XdagBlock.XDAG_BLOCK_SIZE; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_NONCE; -import static io.xdag.net.message.XdagMessageCodes.SUMS_REPLY; - -import io.xdag.core.XdagStats; -import io.xdag.utils.BytesUtils; -import java.math.BigInteger; -import java.nio.ByteOrder; -import java.util.zip.CRC32; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes; -import org.apache.tuweni.bytes.MutableBytes32; - -@EqualsAndHashCode(callSuper = false) -public abstract class AbstractMessage extends Message { - - @Getter - @Setter - protected long starttime; - - @Getter - @Setter - protected long endtime; - - @Getter - @Setter - protected long random; - - @Getter - @Setter - protected Bytes32 hash; - - - /** - * 获取对方节点的netstatus - */ - @Setter - protected XdagStats xdagStats; - /** - * 获取对方节点的netdb - */ - protected NetDB netDB; - protected XdagMessageCodes codes; - - /** - * 本地net DB - */ - protected NetDB currentDB; - - - public AbstractMessage( - XdagMessageCodes type, long starttime, long endtime, long random, XdagStats xdagStats, NetDB currentDB) { - parsed = true; - this.starttime = starttime; - this.endtime = endtime; - this.random = random; - this.xdagStats = xdagStats; - this.codes = type; - this.currentDB = currentDB; - encode(); - } - - public AbstractMessage(XdagMessageCodes type, long starttime, long endtime, Bytes32 hash, XdagStats xdagStats, - NetDB currentDB) { - parsed = true; - this.starttime = starttime; - this.endtime = endtime; - this.hash = hash; - this.xdagStats = xdagStats; - this.codes = type; - this.currentDB = currentDB; - encode(); - } - - public AbstractMessage(MutableBytes data) { - super(data); - parse(); - } - - public XdagStats getXdagStats() { - return xdagStats; - } - - public NetDB getNetDB() { - return netDB; - } - - public void parse() { - if (parsed) { - return; - } - starttime = encoded.getLong(16, ByteOrder.LITTLE_ENDIAN); - endtime = encoded.getLong(24, ByteOrder.LITTLE_ENDIAN); - random = encoded.getLong(32, ByteOrder.LITTLE_ENDIAN); - BigInteger maxdifficulty = encoded.slice(80, 16).toUnsignedBigInteger(ByteOrder.LITTLE_ENDIAN); - long totalnblocks = encoded.getLong(104, ByteOrder.LITTLE_ENDIAN); - long totalnmains = encoded.getLong(120, ByteOrder.LITTLE_ENDIAN); - int totalnhosts = encoded.getInt(132, ByteOrder.LITTLE_ENDIAN); - long maintime = encoded.getLong(136, ByteOrder.LITTLE_ENDIAN); - xdagStats = new XdagStats(maxdifficulty, totalnblocks, totalnmains, totalnhosts, maintime); - - // test netdb - int length = getCommand() == SUMS_REPLY ? 6 : 14; - // 80 是sizeof(xdag_stats) - byte[] netdb = new byte[length * 32 - 80]; - System.arraycopy(encoded.toArray(), 144, netdb, 0, length * 32 - 80); - netDB = new NetDB(netdb); - - parsed = true; - } - - public void encode() { - parsed = true; - encoded = MutableBytes.create(512); - int ttl = 1; - long transportheader = (ttl << 8) | DNET_PKT_XDAG | (XDAG_BLOCK_SIZE << 16); - long type = (codes.asByte() << 4) | XDAG_FIELD_NONCE.asByte(); - - BigInteger diff = xdagStats.difficulty; - BigInteger maxDiff = xdagStats.maxdifficulty; - long nmain = xdagStats.nmain; - long totalMainNumber = Math.max(xdagStats.totalnmain, nmain); - long nblocks = xdagStats.nblocks; - long totalBlockNumber = xdagStats.totalnblocks; - - MutableBytes mutableBytes = MutableBytes.create(112); - long nhosts = currentDB.getIpList().size(); - long totalHosts = currentDB.getIpList().size(); - - mutableBytes.set(0, Bytes.wrap(BytesUtils.longToBytes(nhosts, true))); - mutableBytes.set(8, Bytes.wrap(BytesUtils.longToBytes(totalHosts, true))); - mutableBytes.set(16, Bytes.wrap(currentDB.getEncoded())); - -// // TODO:后续根据ip替换 -// String tmp = "04000000040000003ef4780100000000" + "7f000001611e7f000001b8227f0000015f767f000001d49d"; -// // net 相关 -// byte[] tmpbyte = Hex.decode(tmp); - - // add netdb - // byte[] iplist = netDB.encode(netDB.getActiveIP()); - - // field 0 and field1 - MutableBytes32 first = MutableBytes32.create(); - first.set(0, Bytes.wrap(BytesUtils.longToBytes(transportheader, true))); - first.set(8, Bytes.wrap(BytesUtils.longToBytes(type, true))); - first.set(16, Bytes.wrap(BytesUtils.longToBytes(starttime, true))); - first.set(24, Bytes.wrap(BytesUtils.longToBytes(endtime, true))); - - encoded.set(0, first); - encoded.set(32, Bytes.wrap(BytesUtils.longToBytes(random, true))); - - // field2 diff and maxdiff - encoded.set(64, Bytes.wrap(BytesUtils.bigIntegerToBytes(diff, 16, true))); - encoded.set(80, Bytes.wrap(BytesUtils.bigIntegerToBytes(maxDiff, 16, true))); - - // field3 nblock totalblock main totalmain - encoded.set(96, Bytes.wrap(BytesUtils.longToBytes(nblocks, true))); - encoded.set(104, Bytes.wrap(BytesUtils.longToBytes(totalBlockNumber, true))); - encoded.set(112, Bytes.wrap(BytesUtils.longToBytes(nmain, true))); - encoded.set(120, Bytes.wrap(BytesUtils.longToBytes(totalMainNumber, true))); -// encoded.set(128, Bytes.wrap(tmpbyte)); - encoded.set(128, Bytes.wrap(mutableBytes)); - } - - public void updateCrc() { - CRC32 crc32 = new CRC32(); - crc32.update(encoded.toArray(), 0, 512); - encoded.set(4, Bytes.wrap(BytesUtils.intToBytes((int) crc32.getValue(), true))); - } - -} diff --git a/src/main/java/io/xdag/net/message/Message.java b/src/main/java/io/xdag/net/message/Message.java index ff72623fb..49b6a2b3c 100644 --- a/src/main/java/io/xdag/net/message/Message.java +++ b/src/main/java/io/xdag/net/message/Message.java @@ -27,30 +27,39 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.MutableBytes; -public abstract class Message { - - protected boolean parsed; - protected MutableBytes encoded; - protected byte code; - - public Message() { - } +import lombok.Getter; - public Message(MutableBytes encoded) { - this.encoded = encoded; - parsed = false; - } +@Getter +public abstract class Message { - public abstract Bytes getEncoded(); + /** + * Message code. + */ + protected final MessageCode code; - public abstract Class getAnswerMessage(); + /** + * Response message class. + */ + protected final Class responseMessageClass; - public abstract XdagMessageCodes getCommand(); + /** + * Message body. + */ + protected byte[] body; - public byte getCode() { - return code; + /** + * Create a message instance. + */ + public Message(MessageCode code, Class responseMessageClass) { + this.code = code; + this.responseMessageClass = responseMessageClass; + this.body = Bytes.EMPTY.toArray(); } - @Override - public abstract String toString(); + /** + * Return the message name. + */ + public String toString() { + return getClass().getName(); + } } diff --git a/src/main/java/io/xdag/net/message/MessageCode.java b/src/main/java/io/xdag/net/message/MessageCode.java new file mode 100644 index 000000000..02b3b6fcf --- /dev/null +++ b/src/main/java/io/xdag/net/message/MessageCode.java @@ -0,0 +1,117 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message; + +import lombok.Getter; + +@Getter +public enum MessageCode { + + // ======================================= + // [0x00, 0x2f] Reserved for p2p basics + // ======================================= + + /** + * [0x00] Inform peer of disconnecting. + */ + DISCONNECT(0x00), + + /** + * [0x01] First message over connection. No messages should be sent until + * receiving a response. + */ + /** + * [0x01] A message containing a random bytes + */ + HANDSHAKE_INIT(0x01), + + /** + * [0x02] The new HELLO message + */ + HANDSHAKE_HELLO(0x02), + + /** + * [0x13] The new WORLD message. + */ + HANDSHAKE_WORLD(0x03), + + /** + * [0x04] Request an immediate reply from the peer. + */ + PING(0x04), + + /** + * [0x05] Response to a PING message. + */ + PONG(0x05), + +// /** +// * [0x06] Request peer to provide a list of known nodes. +// */ +// GET_NODES(0x06), +// +// /** +// * [0x07] Response to a GET_NODES message. +// */ +// NODES(0x07), + + // ======================================= + // [0x10, 0x1f] Reserved for node + // ======================================= + BLOCKS_REQUEST(0x10), + BLOCKS_REPLY(0x11), + SUMS_REQUEST(0x12), + SUMS_REPLY(0x13), + BLOCKEXT_REQUEST(0x14), + BLOCKEXT_REPLY(0x15), + BLOCK_REQUEST(0x16), +// RECEIVE_BLOCK(0x17), + NEW_BLOCK(0x18), + SYNC_BLOCK(0x19), + SYNCBLOCK_REQUEST(0x1A); + + + private static final MessageCode[] map = new MessageCode[256]; + + static { + for (MessageCode mc : MessageCode.values()) { + map[mc.code] = mc; + } + } + + public static MessageCode of(int code) { + return map[0xff & code]; + } + + private int code; + + MessageCode(int code) { + this.code = code; + } + + public byte toByte() { + return (byte) code; + } + +} diff --git a/src/main/java/io/xdag/net/libp2p/LibP2PNodeId.java b/src/main/java/io/xdag/net/message/MessageException.java similarity index 72% rename from src/main/java/io/xdag/net/libp2p/LibP2PNodeId.java rename to src/main/java/io/xdag/net/message/MessageException.java index 885cbf385..f53454bab 100644 --- a/src/main/java/io/xdag/net/libp2p/LibP2PNodeId.java +++ b/src/main/java/io/xdag/net/message/MessageException.java @@ -21,28 +21,27 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message; -package io.xdag.net.libp2p; +import java.io.IOException; -import io.libp2p.core.PeerId; -import io.xdag.net.libp2p.peer.NodeId; -import org.apache.tuweni.bytes.Bytes; +public class MessageException extends IOException { -public class LibP2PNodeId extends NodeId { + private static final long serialVersionUID = 1L; - private final PeerId peerId; + public MessageException() { + } - public LibP2PNodeId(final PeerId peerId) { - this.peerId = peerId; + public MessageException(String s) { + super(s); } - @Override - public Bytes toBytes() { - return Bytes.wrap(peerId.getBytes()); + public MessageException(String s, Throwable throwable) { + super(s, throwable); } - @Override - public String toBase58() { - return peerId.toBase58(); + public MessageException(Throwable throwable) { + super(throwable); } + } diff --git a/src/main/java/io/xdag/net/message/MessageFactory.java b/src/main/java/io/xdag/net/message/MessageFactory.java index 7dd9cf286..19c39f13c 100644 --- a/src/main/java/io/xdag/net/message/MessageFactory.java +++ b/src/main/java/io/xdag/net/message/MessageFactory.java @@ -24,10 +24,81 @@ package io.xdag.net.message; -import org.apache.tuweni.bytes.MutableBytes; +import io.xdag.net.message.consensus.BlockExtReplyMessage; +import io.xdag.net.message.consensus.BlockExtRequestMessage; +import io.xdag.net.message.consensus.BlockRequestMessage; +import io.xdag.net.message.consensus.BlocksReplyMessage; +import io.xdag.net.message.consensus.BlocksRequestMessage; +import io.xdag.net.message.consensus.NewBlockMessage; +import io.xdag.net.message.consensus.SumReplyMessage; +import io.xdag.net.message.consensus.SumRequestMessage; +import io.xdag.net.message.p2p.DisconnectMessage; +import io.xdag.net.message.p2p.HelloMessage; +import io.xdag.net.message.p2p.InitMessage; +import io.xdag.net.message.p2p.PingMessage; +import io.xdag.net.message.p2p.PongMessage; +import io.xdag.net.message.p2p.WorldMessage; +import io.xdag.utils.exception.UnreachableException; +import lombok.extern.slf4j.Slf4j; -public interface MessageFactory { +@Slf4j +public class MessageFactory { + /** + * Decode a raw message. + * + * @param code + * The message code + * @param body + * The message body + * @return The decoded message, or NULL if the message type is not unknown + * @throws MessageException + * when the encoding is illegal + */ + public Message create(byte code, byte[] body) throws MessageException { - Message create(byte code, MutableBytes encoded); + MessageCode c = MessageCode.of(code); + if (c == null) { + //log.debug("Invalid message code: {}", Hex.encode0x(Bytes.of(code))); + return null; + } + + try { + switch (c) { + case HANDSHAKE_INIT: + return new InitMessage(body); + case HANDSHAKE_HELLO: + return new HelloMessage(body); + case HANDSHAKE_WORLD: + return new WorldMessage(body); + case DISCONNECT: + return new DisconnectMessage(body); + case PING: + return new PingMessage(body); + case PONG: + return new PongMessage(body); + case BLOCKS_REQUEST: + return new BlocksRequestMessage(body); + case BLOCKS_REPLY: + return new BlocksReplyMessage(body); + case SUMS_REQUEST: + return new SumRequestMessage(body); + case SUMS_REPLY: + return new SumReplyMessage(body); + case BLOCKEXT_REQUEST: + return new BlockExtRequestMessage(body); + case BLOCKEXT_REPLY: + return new BlockExtReplyMessage(body); + case BLOCK_REQUEST: + return new BlockRequestMessage(body); + case NEW_BLOCK: + return new NewBlockMessage(body); + + default: + throw new UnreachableException(); + } + } catch (Exception e) { + throw new MessageException("Failed to decode message", e); + } + } } diff --git a/src/main/java/io/xdag/net/message/MessageQueue.java b/src/main/java/io/xdag/net/message/MessageQueue.java index 0b06f6035..0e647fbf5 100644 --- a/src/main/java/io/xdag/net/message/MessageQueue.java +++ b/src/main/java/io/xdag/net/message/MessageQueue.java @@ -28,13 +28,16 @@ import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.xdag.net.Channel; +import io.xdag.config.Config; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import io.xdag.net.message.p2p.DisconnectMessage; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.concurrent.BasicThreadFactory; @@ -46,20 +49,21 @@ public class MessageQueue { .namingPattern("MessageQueueTimer-thread-%d") .daemon(true) .build()); - private final Queue requestQueue = new ConcurrentLinkedQueue<>(); - private final Queue respondQueue = new ConcurrentLinkedQueue<>(); - private final Channel channel; - boolean isRunning = false; - private ChannelHandlerContext ctx = null; + private final Config config; + + private final Queue queue = new ConcurrentLinkedQueue<>(); + private final Queue prioritized = new ConcurrentLinkedQueue<>(); + private ChannelHandlerContext ctx; private ScheduledFuture timerTask; - public MessageQueue(Channel channel) { - this.channel = channel; + private final AtomicBoolean isClosed = new AtomicBoolean(false); + + public MessageQueue(Config config) { + this.config = config; } - public void activate(ChannelHandlerContext ctx) { + public synchronized void activate(ChannelHandlerContext ctx) { this.ctx = ctx; - isRunning = true; timerTask = timer.scheduleAtFixedRate( () -> { try { @@ -74,58 +78,53 @@ public void activate(ChannelHandlerContext ctx) { TimeUnit.MILLISECONDS); } + public synchronized void deactivate() { + this.timerTask.cancel(false); + } - private void nudgeQueue() { - int n = Math.min(5, size()); - if (n == 0) { - return; - } - // write out n messages - for (int i = 0; i < n; i++) { - // Now send the next message - // log.debug("Sent to Wire with the message,msg:"+msg.getCommand()); - Message respondMsg = respondQueue.poll(); - Message requestMsg = requestQueue.poll(); - if (respondMsg != null) { - ctx.write(respondMsg).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); - } - if (requestMsg != null) { - ctx.write(requestMsg).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); - } + public boolean isIdle() { + return size() == 0; + } + + public void disconnect(ReasonCode code) { + log.debug("Actively closing the connection: reason = {}", code); + // avoid repeating close requests + if (isClosed.compareAndSet(false, true)) { + ctx.writeAndFlush(new DisconnectMessage(code)).addListener((ChannelFutureListener) future -> ctx.close()); } - ctx.flush(); } - public void sendMessage(Message msg) { - if (channel.isDisconnected()) { - log.warn("{}: attempt to send [{}] message after disconnect", channel, msg.getCommand().name()); - return; + public boolean sendMessage(Message msg) { + if (size() >= config.getNodeSpec().getNetMaxMessageQueueSize()) { + disconnect(ReasonCode.MESSAGE_QUEUE_FULL); + return false; } - if (msg.getAnswerMessage() != null) { - requestQueue.add(msg); + if (config.getNodeSpec().getNetPrioritizedMessages().contains(msg.getCode())) { + prioritized.add(msg); } else { - respondQueue.add(msg); + queue.add(msg); } + return true; } - public void disconnect() { - ctx.close(); + public int size() { + return queue.size() + prioritized.size(); } - public void close() { - isRunning = false; - if (timerTask != null) { - timerTask.cancel(false); + private void nudgeQueue() { + int n = Math.min(5, size()); + if (n == 0) { + return; } - } - - public boolean isRunning() { - return isRunning; - } + // write out n messages + for (int i = 0; i < n; i++) { + Message msg = !prioritized.isEmpty() ? prioritized.poll() : queue.poll(); - public int size() { - return requestQueue.size() + respondQueue.size(); + log.trace("Wiring message: {}", msg); + ctx.write(msg).addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); + } + ctx.flush(); } } diff --git a/src/main/java/io/xdag/config/spec/PoolSpec.java b/src/main/java/io/xdag/net/message/ReasonCode.java similarity index 52% rename from src/main/java/io/xdag/config/spec/PoolSpec.java rename to src/main/java/io/xdag/net/message/ReasonCode.java index 93a1b755e..28af01999 100644 --- a/src/main/java/io/xdag/config/spec/PoolSpec.java +++ b/src/main/java/io/xdag/net/message/ReasonCode.java @@ -21,68 +21,78 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message; -package io.xdag.config.spec; - -/** - * The Mining Pool Specifications - */ -public interface PoolSpec { - - String getPoolIp(); - - int getPoolPort(); - - String getPoolTag(); - - int getGlobalMinerLimit(); - - int getGlobalMinerChannelLimit(); - - int getMaxConnectPerIp(); +public enum ReasonCode { /** - * 拥有相同地址块的矿工最多允许同时在线的数量 g_connections_per_miner_limit + * [0x00] Bad network. */ - int getMaxMinerPerAccount(); - - int getMaxShareCountPerChannel(); - - int getConnectionTimeout(); + BAD_NETWORK(0x00), + /** + * [0x01] Incompatible protocol. + */ + BAD_NETWORK_VERSION(0x01), /** - * 矿池自己的收益占比 + * [0x02] Too many active peers. */ - double getPoolRation(); + TOO_MANY_PEERS(0x02), /** - * 出块矿工收益占比 + * [0x03] Invalid handshake message. */ - double getRewardRation(); + INVALID_HANDSHAKE(0x03), /** - * 基金会收益占比 + * [0x04] Duplicated peerId. */ - double getFundRation(); + DUPLICATED_PEER_ID(0x04), /** - * 参与奖励的占比 + * [0x05] The message queue is full. */ - double getDirectRation(); + MESSAGE_QUEUE_FULL(0x05), /** - * 奖励支付的周期 + * [0x06] Another validator peer tries to connect using the same IP. */ - int getAwardEpoch(); + VALIDATOR_IP_LIMITED(0x06), /** - * 等待超过10个epoch默认启动挖矿 + * [0x07] The peer tries to re-handshake. */ - int getWaitEpoch(); + HANDSHAKE_EXISTS(0x07), /** - * 基金会地址 + * [0x08] The manifests malicious behavior. */ - String getFundAddress(); + BAD_PEER(0x08); + + private int code; + + private static final ReasonCode[] intToCode = new ReasonCode[256]; + + static { + for (ReasonCode mc : ReasonCode.values()) { + intToCode[mc.code] = mc; + } + } + + public static ReasonCode of(int code) { + return intToCode[0xff & code]; + } + + ReasonCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + + public byte toByte() { + return (byte) code; + } } diff --git a/src/main/java/io/xdag/net/message/XdagMessageCodes.java b/src/main/java/io/xdag/net/message/XdagMessageCodes.java deleted file mode 100644 index e1b8a0f41..000000000 --- a/src/main/java/io/xdag/net/message/XdagMessageCodes.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message; - -import static io.xdag.net.XdagVersion.V03; - -import com.google.common.collect.Maps; -import io.xdag.net.XdagVersion; -import java.util.Map; - -/** - * xdag block.h - * - *

- * enum xdag_message_type { - * XDAG_MESSAGE_BLOCKS_REQUEST, - * XDAG_MESSAGE_BLOCKS_REPLY, - * XDAG_MESSAGE_SUMS_REQUEST, - * XDAG_MESSAGE_SUMS_REPLY, - * XDAG_MESSAGE_BLOCKEXT_REQUEST, - * XDAG_MESSAGE_BLOCKEXT_REPLY, - * XDAG_MESSAGE_BLOCK_REQUEST - * }; - */ -public enum XdagMessageCodes { - // add new block type here - BLOCKS_REQUEST(0x00), - BLOCKS_REPLY(0x01), - SUMS_REQUEST(0x02), - SUMS_REPLY(0x03), - BLOCKEXT_REQUEST(0x04), - BLOCKEXT_REPLY(0x05), - BLOCK_REQUEST(0x06), - - // add new block type here - Receive_Block(0x07), - TASK_SHARE(0x08), - NEW_TASK(0x09), - NEW_BALANCE(0x0A), - NEW_BLOCK(0x0B), - WORKER_NAME(0x0C), - SYNC_BLOCK(0x0D), - SYNCBLOCK_REQUEST(0x0E); - - private static final Map> intToTypeMap = Maps.newHashMap(); - private static final Map versionToValuesMap = Maps.newHashMap(); - - static { - versionToValuesMap.put( - V03, - new XdagMessageCodes[]{ - BLOCKS_REQUEST, - BLOCKS_REPLY, - SUMS_REQUEST, - SUMS_REPLY, - BLOCKEXT_REQUEST, - BLOCKEXT_REPLY, - BLOCK_REQUEST, - Receive_Block, - TASK_SHARE, - NEW_TASK, - NEW_BALANCE, - NEW_BLOCK, - WORKER_NAME, - SYNC_BLOCK, - SYNCBLOCK_REQUEST - }); - - for (XdagVersion v : XdagVersion.values()) { - Map map = Maps.newHashMap(); - intToTypeMap.put(v, map); - for (XdagMessageCodes code : values(v)) { - map.put(code.cmd, code); - } - } - } - - private final int cmd; - - XdagMessageCodes(int cmd) { - this.cmd = cmd; - } - - public static XdagMessageCodes[] values(XdagVersion v) { - return versionToValuesMap.get(v); - } - - public static XdagMessageCodes fromByte(byte i, XdagVersion v) { - Map map = intToTypeMap.get(v); - return map.get((int) i); - } - - public static boolean inRange(byte code, XdagVersion v) { - XdagMessageCodes[] codes = values(v); - return code >= codes[0].asByte() && code <= codes[codes.length - 1].asByte(); - } - - public byte asByte() { - return (byte) (cmd); - } -} diff --git a/src/main/java/io/xdag/net/handler/XdagHandlerFactory.java b/src/main/java/io/xdag/net/message/consensus/BlockExtReplyMessage.java similarity index 79% rename from src/main/java/io/xdag/net/handler/XdagHandlerFactory.java rename to src/main/java/io/xdag/net/message/consensus/BlockExtReplyMessage.java index 7d2fb8212..f7a2071ba 100644 --- a/src/main/java/io/xdag/net/handler/XdagHandlerFactory.java +++ b/src/main/java/io/xdag/net/message/consensus/BlockExtReplyMessage.java @@ -21,13 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.consensus; -package io.xdag.net.handler; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; -import io.xdag.net.XdagVersion; +public class BlockExtReplyMessage extends Message { -public interface XdagHandlerFactory { - - XdagHandler create(XdagVersion version); + public BlockExtReplyMessage(byte[] body) { + super(MessageCode.BLOCKEXT_REPLY, null); + this.body = body; + } } diff --git a/src/main/java/io/xdag/config/PoolConfig.java b/src/main/java/io/xdag/net/message/consensus/BlockExtRequestMessage.java similarity index 81% rename from src/main/java/io/xdag/config/PoolConfig.java rename to src/main/java/io/xdag/net/message/consensus/BlockExtRequestMessage.java index 184a4d406..3f4dc14f0 100644 --- a/src/main/java/io/xdag/config/PoolConfig.java +++ b/src/main/java/io/xdag/net/message/consensus/BlockExtRequestMessage.java @@ -21,17 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.config; +package io.xdag.net.message.consensus; +import io.xdag.net.message.MessageCode; -import lombok.Builder; -import lombok.Data; - -@Data -@Builder -public class PoolConfig { - double poolRation; - double minerRewardRation; - double fundRation; - double directRation; +public class BlockExtRequestMessage extends XdagMessage { + public BlockExtRequestMessage(byte[] body) { + super(MessageCode.BLOCKEXT_REQUEST, BlocksReplyMessage.class, body); + } } diff --git a/src/main/java/io/xdag/net/message/consensus/BlockRequestMessage.java b/src/main/java/io/xdag/net/message/consensus/BlockRequestMessage.java new file mode 100644 index 000000000..bbba6223e --- /dev/null +++ b/src/main/java/io/xdag/net/message/consensus/BlockRequestMessage.java @@ -0,0 +1,44 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.consensus; + + + +import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.bytes.MutableBytes; + +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; + +public class BlockRequestMessage extends XdagMessage { + + public BlockRequestMessage(MutableBytes hash, XdagStats xdagStats, NetDB localNetdb) { + super(MessageCode.BLOCK_REQUEST, null, 0, 0, Bytes32.wrap(hash), xdagStats, localNetdb); + } + + public BlockRequestMessage(byte[] body) { + super(MessageCode.BLOCK_REQUEST, null, body); + } +} diff --git a/src/main/java/io/xdag/net/message/consensus/BlocksReplyMessage.java b/src/main/java/io/xdag/net/message/consensus/BlocksReplyMessage.java new file mode 100644 index 000000000..a81f17bf2 --- /dev/null +++ b/src/main/java/io/xdag/net/message/consensus/BlocksReplyMessage.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.consensus; + +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; + +public class BlocksReplyMessage extends XdagMessage { + + public BlocksReplyMessage(long starttime, long endtime, long random, XdagStats xdagStats, NetDB localNetdb) { + super(MessageCode.BLOCKS_REPLY, null, starttime, endtime, random, xdagStats, localNetdb); + } + + public BlocksReplyMessage(byte[] body) { + super(MessageCode.BLOCKS_REPLY, null, body); + } + +} diff --git a/src/main/java/io/xdag/net/libp2p/peer/NodeId.java b/src/main/java/io/xdag/net/message/consensus/BlocksRequestMessage.java similarity index 67% rename from src/main/java/io/xdag/net/libp2p/peer/NodeId.java rename to src/main/java/io/xdag/net/message/consensus/BlocksRequestMessage.java index 25b02c08f..ac190956c 100644 --- a/src/main/java/io/xdag/net/libp2p/peer/NodeId.java +++ b/src/main/java/io/xdag/net/message/consensus/BlocksRequestMessage.java @@ -21,33 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.consensus; -package io.xdag.net.libp2p.peer; +import org.apache.commons.lang3.RandomUtils; +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; -import org.apache.tuweni.bytes.Bytes; - -public abstract class NodeId { - - public abstract Bytes toBytes(); - - public abstract String toBase58(); - - @Override - public final int hashCode() { - return toBytes().hashCode(); - } - - @Override - public final boolean equals(final Object obj) { - if (!(obj instanceof NodeId)) { - return false; - } - return toBytes().equals(((NodeId) obj).toBytes()); +public class BlocksRequestMessage extends XdagMessage { + public BlocksRequestMessage(long starttime, long endtime, XdagStats xdagStats, NetDB localNetdb) { + super(MessageCode.BLOCKEXT_REQUEST, null, starttime, endtime, RandomUtils.nextLong(), xdagStats, localNetdb); } - @Override - public final String toString() { - return toBase58(); + public BlocksRequestMessage(byte[] body) { + super(MessageCode.BLOCKEXT_REQUEST, null, body); } } \ No newline at end of file diff --git a/src/main/java/io/xdag/mine/message/NewTaskMessage.java b/src/main/java/io/xdag/net/message/consensus/NewBlockMessage.java similarity index 52% rename from src/main/java/io/xdag/mine/message/NewTaskMessage.java rename to src/main/java/io/xdag/net/message/consensus/NewBlockMessage.java index 427fa2458..f382d0ca0 100644 --- a/src/main/java/io/xdag/mine/message/NewTaskMessage.java +++ b/src/main/java/io/xdag/net/message/consensus/NewBlockMessage.java @@ -21,50 +21,58 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.consensus; -package io.xdag.mine.message; +import static io.xdag.config.Constants.DNET_PKT_XDAG; -import static io.xdag.net.message.XdagMessageCodes.NEW_TASK; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.MutableBytes; -import io.xdag.core.XdagField; +import io.xdag.core.Block; +import io.xdag.core.SimpleEncoder; +import io.xdag.core.XdagBlock; import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; +import lombok.Setter; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; +@Getter +@Setter +public class NewBlockMessage extends Message { -public class NewTaskMessage extends Message { + private XdagBlock xdagBlock; + private Block block; + private int ttl; - private final XdagField[] xdagFields = new XdagField[2]; + public NewBlockMessage(byte[] body) { + super(MessageCode.NEW_BLOCK, null); - public NewTaskMessage(MutableBytes bytes) { - super(bytes); - xdagFields[0] = new XdagField(bytes.mutableSlice(0, 32)); - xdagFields[1] = new XdagField(bytes.mutableSlice(32, 32)); - } + SimpleDecoder dec = new SimpleDecoder(body); - @Override - public Bytes getEncoded() { - MutableBytes data = MutableBytes.create(64); - data.set(0, xdagFields[0].getData()); - data.set(32, xdagFields[1].getData()); - return data; + this.body = dec.readBytes(); + this.xdagBlock = new XdagBlock(this.body); + this.block = new Block(this.xdagBlock); + this.ttl = dec.readInt(); } - @Override - public Class getAnswerMessage() { - return null; - } + public NewBlockMessage(Block block, int ttl) { + super(MessageCode.NEW_BLOCK, null); + + this.block = block; + this.ttl = ttl; - @Override - public XdagMessageCodes getCommand() { - return NEW_TASK; + SimpleEncoder enc = encode(); + this.body = enc.toBytes(); } - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); + private SimpleEncoder encode() { + SimpleEncoder enc = new SimpleEncoder(); + enc.writeBytes(this.block.toBytes()); + enc.writeInt(ttl); + return enc; } + + } diff --git a/src/main/java/io/xdag/mine/message/WorkerNameMessage.java b/src/main/java/io/xdag/net/message/consensus/SumReplyMessage.java similarity index 54% rename from src/main/java/io/xdag/mine/message/WorkerNameMessage.java rename to src/main/java/io/xdag/net/message/consensus/SumReplyMessage.java index 97dceb537..2ae5ea80b 100644 --- a/src/main/java/io/xdag/mine/message/WorkerNameMessage.java +++ b/src/main/java/io/xdag/net/message/consensus/SumReplyMessage.java @@ -21,45 +21,46 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.mine.message; +package io.xdag.net.message.consensus; -import static io.xdag.net.message.XdagMessageCodes.WORKER_NAME; +import java.math.BigInteger; -import io.xdag.core.XdagField; -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; - -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.MutableBytes; -public class WorkerNameMessage extends Message { +import io.xdag.core.SimpleEncoder; +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; +import io.xdag.utils.Numeric; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; +import lombok.Setter; - private final XdagField xdagField; +@Getter +@Setter +public class SumReplyMessage extends XdagMessage { - public WorkerNameMessage(MutableBytes encoded) { - super(encoded); - this.xdagField = new XdagField(encoded); - } + MutableBytes sum; - @Override - public Bytes getEncoded() { - return xdagField.getData(); + public SumReplyMessage(long endtime, long random, XdagStats xdagStats, MutableBytes sum, NetDB localNetdb) { + super(MessageCode.SUMS_REPLY, null, 1, endtime, random, xdagStats, localNetdb); + this.sum = sum; } - @Override - public Class getAnswerMessage() { - return null; - } + public SumReplyMessage(byte[] body) { + super(MessageCode.SUMS_REPLY, null, body); - @Override - public XdagMessageCodes getCommand() { - return WORKER_NAME; + SimpleDecoder dec = super.decode(); + this.sum = MutableBytes.wrap(dec.readBytes()); } @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); + protected SimpleEncoder encode() { + SimpleEncoder enc = super.encode(); + // add sum + enc.writeBytes(sum.toArray()); + return enc; } } diff --git a/src/main/java/io/xdag/net/message/consensus/SumRequestMessage.java b/src/main/java/io/xdag/net/message/consensus/SumRequestMessage.java new file mode 100644 index 000000000..1b42fda10 --- /dev/null +++ b/src/main/java/io/xdag/net/message/consensus/SumRequestMessage.java @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.consensus; + +import org.apache.commons.lang3.RandomUtils; + +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; + +public class SumRequestMessage extends XdagMessage { + public SumRequestMessage(long starttime, long endtime, XdagStats xdagStats, NetDB localNetdb) { + super(MessageCode.SUMS_REQUEST, SumReplyMessage.class, starttime, endtime, RandomUtils.nextLong(), xdagStats, localNetdb); + } + + public SumRequestMessage(byte[] body) { + super(MessageCode.SUMS_REQUEST, SumReplyMessage.class, body); + } +} diff --git a/src/main/java/io/xdag/net/message/consensus/SyncBlockMessage.java b/src/main/java/io/xdag/net/message/consensus/SyncBlockMessage.java new file mode 100644 index 000000000..bd75c9e26 --- /dev/null +++ b/src/main/java/io/xdag/net/message/consensus/SyncBlockMessage.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.consensus; + +import static io.xdag.config.Constants.DNET_PKT_XDAG; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.MutableBytes; + +import io.xdag.core.Block; +import io.xdag.core.SimpleEncoder; +import io.xdag.core.XdagBlock; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class SyncBlockMessage extends Message { + + private XdagBlock xdagBlock; + private Block block; + private int ttl; + + public SyncBlockMessage(byte[] body) { + super(MessageCode.SYNC_BLOCK, null); + + SimpleDecoder dec = new SimpleDecoder(body); + + this.body = dec.readBytes(); + this.xdagBlock = new XdagBlock(this.body); + this.block = new Block(this.xdagBlock); + this.ttl = dec.readInt(); + } + + public SyncBlockMessage(Block block, int ttl) { + super(MessageCode.SYNC_BLOCK, null); + + this.block = block; + this.ttl = ttl; + + SimpleEncoder enc = encode(); + this.body = enc.toBytes(); + } + + private SimpleEncoder encode() { + SimpleEncoder enc = new SimpleEncoder(); + enc.writeBytes(this.block.toBytes()); + enc.writeInt(ttl); + return enc; + } + +} diff --git a/src/main/java/io/xdag/mine/manager/AwardManager.java b/src/main/java/io/xdag/net/message/consensus/SyncBlockRequestMessage.java similarity index 72% rename from src/main/java/io/xdag/mine/manager/AwardManager.java rename to src/main/java/io/xdag/net/message/consensus/SyncBlockRequestMessage.java index 01e6a81c7..9d02d3436 100644 --- a/src/main/java/io/xdag/mine/manager/AwardManager.java +++ b/src/main/java/io/xdag/net/message/consensus/SyncBlockRequestMessage.java @@ -21,24 +21,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.consensus; -package io.xdag.mine.manager; - -import io.xdag.config.PoolConfig; -import io.xdag.consensus.Task; import org.apache.tuweni.bytes.Bytes32; +import org.apache.tuweni.bytes.MutableBytes; -public interface AwardManager { - - void onNewTask(Task task); - - void start(); - - void stop(); +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.MessageCode; - void addAwardBlock(Bytes32 share, Bytes32 hash, long generateTime); +public class SyncBlockRequestMessage extends XdagMessage { - void updatePoolConfig(double poolFeeRation,double poolRewardRation,double poolDirectRation, double poolFundRation); + public SyncBlockRequestMessage(MutableBytes hash, XdagStats xdagStats, NetDB localNetdb) { + super(MessageCode.SYNCBLOCK_REQUEST, SyncBlockMessage.class, 0, 0, Bytes32.wrap(hash), xdagStats, localNetdb); + } - PoolConfig getPoolConfig(); } diff --git a/src/main/java/io/xdag/net/message/consensus/XdagMessage.java b/src/main/java/io/xdag/net/message/consensus/XdagMessage.java new file mode 100644 index 000000000..d783ed120 --- /dev/null +++ b/src/main/java/io/xdag/net/message/consensus/XdagMessage.java @@ -0,0 +1,134 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.consensus; + +import java.math.BigInteger; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; + +import io.xdag.core.SimpleEncoder; +import io.xdag.core.XdagStats; +import io.xdag.net.NetDB; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; +import io.xdag.utils.Numeric; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public abstract class XdagMessage extends Message { + + protected long starttime; + + protected long endtime; + + protected long random; + + protected Bytes32 hash; + + protected XdagStats xdagStats; + + protected NetDB remoteNetdb; + + protected NetDB localNetdb; + + public XdagMessage(MessageCode code, Class responseMessageClass, byte[] body) { + super(code, responseMessageClass); + this.body = body; + decode(); + } + + public XdagMessage(MessageCode code, Class responseMessageClass, long starttime, long endtime, long random, XdagStats xdagStats, NetDB localNetdb) { + super(code, responseMessageClass); + + this.starttime = starttime; + this.endtime = endtime; + this.random = random; + this.xdagStats = xdagStats; + this.localNetdb = localNetdb; + + this.hash = Bytes32.ZERO; + SimpleEncoder enc = encode(); + this.body = enc.toBytes(); + } + + public XdagMessage(MessageCode code, Class responseMessageClass, long starttime, long endtime, Bytes32 hash, XdagStats xdagStats, + NetDB localNetdb) { + super(code, responseMessageClass); + + this.starttime = starttime; + this.endtime = endtime; + this.hash = hash; + this.xdagStats = xdagStats; + this.localNetdb = localNetdb; + + SimpleEncoder enc = encode(); + this.body = enc.toBytes(); + } + + protected SimpleEncoder encode() { + SimpleEncoder enc = new SimpleEncoder(); + + enc.writeLong(starttime); + enc.writeLong(endtime); + enc.writeLong(random); + enc.writeBytes(hash.toArray()); + + enc.writeBytes(BytesUtils.bigIntegerToBytes(xdagStats.maxdifficulty, 16, false)); + + enc.writeLong(xdagStats.totalnblocks); + enc.writeLong(xdagStats.totalnmain); + enc.writeInt(xdagStats.totalnhosts); + enc.writeLong(xdagStats.maintime); + + enc.writeBytes(localNetdb.getEncoded()); + return enc; + } + + protected SimpleDecoder decode() { + SimpleDecoder dec = new SimpleDecoder(this.body); + + this.starttime = dec.readLong(); + this.endtime = dec.readLong(); + this.random = dec.readLong(); + this.hash = Bytes32.wrap(dec.readBytes()); + + BigInteger maxdifficulty = Numeric.toBigInt(dec.readBytes()); + long totalnblocks = dec.readLong(); + long totalnmains = dec.readLong(); + int totalnhosts = dec.readInt(); + long maintime = dec.readLong(); + + xdagStats = new XdagStats(maxdifficulty, totalnblocks, totalnmains, totalnhosts, maintime); + + byte[] netdb = dec.readBytes(); + localNetdb = new NetDB(netdb); + return dec; + } + +} diff --git a/src/main/java/io/xdag/net/message/impl/BlockExtRequestMessage.java b/src/main/java/io/xdag/net/message/impl/BlockExtRequestMessage.java deleted file mode 100644 index 64520d41a..000000000 --- a/src/main/java/io/xdag/net/message/impl/BlockExtRequestMessage.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; - -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -public class BlockExtRequestMessage extends Message { - - public BlockExtRequestMessage(MutableBytes bytes) { - super(bytes); - // TODO Auto-generated constructor stub - } - - @Override - public Class getAnswerMessage() { - // TODO Auto-generated method stub - return BlocksReplyMessage.class; - } - - @Override - public Bytes getEncoded() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.BLOCKEXT_REQUEST; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/BlockRequestMessage.java b/src/main/java/io/xdag/net/message/impl/BlockRequestMessage.java deleted file mode 100644 index 672f63972..000000000 --- a/src/main/java/io/xdag/net/message/impl/BlockRequestMessage.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.config.Constants.DNET_PKT_XDAG; -import static io.xdag.core.XdagBlock.XDAG_BLOCK_SIZE; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_NONCE; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.utils.BytesUtils; -import java.math.BigInteger; -import java.nio.ByteOrder; -import lombok.EqualsAndHashCode; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes; -import org.apache.tuweni.bytes.MutableBytes32; - -@EqualsAndHashCode(callSuper = false) -public class BlockRequestMessage extends AbstractMessage { - - public BlockRequestMessage(MutableBytes hash, XdagStats xdagStats, NetDB currentDB) { - super(XdagMessageCodes.BLOCK_REQUEST, 0, 0, Bytes32.wrap(hash), xdagStats, currentDB); - } - - public BlockRequestMessage(MutableBytes hash) { - super(hash); - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public Bytes getEncoded() { - // TODO Auto-generated method stub - return encoded; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + starttime - + " endtime=" - + this.endtime - + " hash=" - + hash.toHexString() - + " netstatus=" - + xdagStats; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.BLOCK_REQUEST; - } - - @Override - public void encode() { - parsed = true; - encoded = MutableBytes.create(512); - int ttl = 1; - long transportheader = (ttl << 8) | DNET_PKT_XDAG | (XDAG_BLOCK_SIZE << 16); - long type = (codes.asByte() << 4) | XDAG_FIELD_NONCE.asByte(); - - BigInteger diff = xdagStats.getDifficulty(); - BigInteger maxDiff = xdagStats.getMaxdifficulty(); - long nmain = xdagStats.getNmain(); - long totalMainNumber = Math.max(xdagStats.getTotalnmain(), nmain); - long nblocks = xdagStats.getNblocks(); - long totalBlockNumber = xdagStats.getTotalnblocks(); - - MutableBytes mutableBytes = MutableBytes.create(112); - long nhosts = currentDB.getIpList().size(); - long totalHosts = currentDB.getIpList().size(); - - mutableBytes.set(0, Bytes.wrap(BytesUtils.longToBytes(nhosts, true))); - mutableBytes.set(8, Bytes.wrap(BytesUtils.longToBytes(totalHosts, true))); - mutableBytes.set(16, Bytes.wrap(currentDB.getEncoded())); - -// // TODO:后续根据ip替换 -// String tmp = "04000000040000003ef4780100000000" + "7f000001611e7f000001b8227f0000015f767f000001d49d"; -// // net 相关 -// byte[] tmpbyte = Hex.decode(tmp); - - // field 0 and field1 - MutableBytes32 first = MutableBytes32.create(); - first.set(0, Bytes.wrap(BytesUtils.longToBytes(transportheader, true))); - first.set(8, Bytes.wrap(BytesUtils.longToBytes(type, true))); - first.set(16, Bytes.wrap(BytesUtils.longToBytes(starttime, true))); - first.set(24, Bytes.wrap(BytesUtils.longToBytes(endtime, true))); - - encoded.set(0, first); - encoded.set(32, hash.reverse()); - - // field2 diff and maxdiff - encoded.set(64, Bytes.wrap(BytesUtils.bigIntegerToBytes(diff, 16, true))); - encoded.set(80, Bytes.wrap(BytesUtils.bigIntegerToBytes(maxDiff, 16, true))); - - // field3 nblock totalblock main totalmain - encoded.set(96, Bytes.wrap(BytesUtils.longToBytes(nblocks, true))); - encoded.set(104, Bytes.wrap(BytesUtils.longToBytes(totalBlockNumber, true))); - encoded.set(112, Bytes.wrap(BytesUtils.longToBytes(nmain, true))); - encoded.set(120, Bytes.wrap(BytesUtils.longToBytes(totalMainNumber, true))); - encoded.set(128, Bytes.wrap(mutableBytes)); - updateCrc(); - } - - @Override - public void parse() { - if (parsed) { - return; - } - - this.starttime = encoded.getLong(16, ByteOrder.LITTLE_ENDIAN); - this.endtime = encoded.getLong(24, ByteOrder.LITTLE_ENDIAN); - BigInteger maxdifficulty = encoded.slice(80, 16).toUnsignedBigInteger(ByteOrder.LITTLE_ENDIAN); - long totalnblocks = encoded.getLong(104, ByteOrder.LITTLE_ENDIAN); - long totalnmains = encoded.getLong(120, ByteOrder.LITTLE_ENDIAN); - int totalnhosts = encoded.getInt(132, ByteOrder.LITTLE_ENDIAN); - long maintime = encoded.getLong(136, ByteOrder.LITTLE_ENDIAN); - xdagStats = new XdagStats(maxdifficulty, totalnblocks, totalnmains, totalnhosts, maintime); - MutableBytes32 hash = MutableBytes32.create(); - hash.set(0, encoded.slice(32, 24)); - this.hash = hash.copy(); - parsed = true; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/BlocksReplyMessage.java b/src/main/java/io/xdag/net/message/impl/BlocksReplyMessage.java deleted file mode 100644 index 3040c20c1..000000000 --- a/src/main/java/io/xdag/net/message/impl/BlocksReplyMessage.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.net.message.XdagMessageCodes.BLOCKS_REPLY; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import lombok.EqualsAndHashCode; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -@EqualsAndHashCode(callSuper = false) -public class BlocksReplyMessage extends AbstractMessage { - - public BlocksReplyMessage(long starttime, long endtime, long random, XdagStats xdagStats, NetDB currentDB) { - super(BLOCKS_REPLY, starttime, endtime, random, xdagStats, currentDB); - updateCrc(); - } - - public BlocksReplyMessage(MutableBytes encoded) { - super(encoded); - } - - @Override - public Bytes getEncoded() { - return encoded; - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.BLOCKS_REPLY; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + getStarttime() - + " endtime=" - + getEndtime() - + " netstatus" - + getXdagStats(); - } -} diff --git a/src/main/java/io/xdag/net/message/impl/BlocksRequestMessage.java b/src/main/java/io/xdag/net/message/impl/BlocksRequestMessage.java deleted file mode 100644 index 893dd4c05..000000000 --- a/src/main/java/io/xdag/net/message/impl/BlocksRequestMessage.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.net.message.XdagMessageCodes.BLOCKS_REQUEST; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import lombok.EqualsAndHashCode; -import org.apache.commons.lang3.RandomUtils; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -@EqualsAndHashCode(callSuper = false) -public class BlocksRequestMessage extends AbstractMessage { - - public BlocksRequestMessage(MutableBytes bytes) { - super(bytes); - } - - public BlocksRequestMessage(long starttime, long endtime, XdagStats xdagStats, NetDB currentDB) { - super(BLOCKS_REQUEST, starttime, endtime, RandomUtils.nextLong(), xdagStats, currentDB); - updateCrc(); - } - - @Override - public Bytes getEncoded() { - if (encoded == null) { - encode(); - } - return encoded; - } - - @Override - public Class getAnswerMessage() { - return BlocksReplyMessage.class; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.BLOCKS_REQUEST; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + this.starttime - + " endtime=" - + this.endtime - + "]"; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/NewBlockMessage.java b/src/main/java/io/xdag/net/message/impl/NewBlockMessage.java deleted file mode 100644 index 41c7708ff..000000000 --- a/src/main/java/io/xdag/net/message/impl/NewBlockMessage.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.config.Constants.DNET_PKT_XDAG; - -import io.xdag.core.Block; -import io.xdag.core.XdagBlock; -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.utils.BytesUtils; -import java.util.zip.CRC32; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -public class NewBlockMessage extends Message { - - private XdagBlock xdagBlock; - private Block block; - private int ttl; - - /** - * 不处理crc - */ - public NewBlockMessage(MutableBytes bytes) { - super(bytes); - } - - /** - * 处理crc 创建新的用于发送Block的message - */ - public NewBlockMessage(Block block, int ttl) { - this.block = block; - this.ttl = ttl; - this.parsed = true; - encode(); - } - - /** - * 不处理crc - */ - public NewBlockMessage(XdagBlock xdagBlock, int ttl) { - super(xdagBlock.getData().mutableCopy()); - this.xdagBlock = xdagBlock; - this.ttl = ttl; - } - - public Block getBlock() { - parse(); - return block; - } - - private void parse() { - if (parsed) { - return; - } - block = new Block(xdagBlock); - parsed = true; - } - - private void encode() { - this.encoded = this.block.getXdagBlock().getData().mutableCopy(); - long transportheader = ((long) ttl << 8) | DNET_PKT_XDAG | (512 << 16); - this.encoded.set(0, Bytes.wrap(BytesUtils.longToBytes(transportheader, true))); - updateCrc(); - } - - public void updateCrc() { - CRC32 crc32 = new CRC32(); - crc32.update(encoded.toArray(), 0, 512); - this.encoded.set(4, Bytes.wrap(BytesUtils.intToBytes((int) crc32.getValue(), true))); - } - - public int getTtl() { - return ttl; - } - - public void setTtl(int ttl) { - this.ttl = ttl; - } - - @Override - public Bytes getEncoded() { - return encoded; - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.NEW_BLOCK; - } - - @Override - public String toString() { - return "NewBlock Message:" + encoded.toHexString(); - } -} diff --git a/src/main/java/io/xdag/net/message/impl/SumReplyMessage.java b/src/main/java/io/xdag/net/message/impl/SumReplyMessage.java deleted file mode 100644 index 33df5b9f4..000000000 --- a/src/main/java/io/xdag/net/message/impl/SumReplyMessage.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.net.message.XdagMessageCodes.SUMS_REPLY; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.utils.BytesUtils; -import java.math.BigInteger; -import java.nio.ByteOrder; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -public class SumReplyMessage extends AbstractMessage { - - MutableBytes sums; - - public SumReplyMessage(long endtime, long random, XdagStats xdagStats, MutableBytes sums, NetDB currentDB) { - super(SUMS_REPLY, 1, endtime, random, xdagStats, currentDB); - this.sums = sums; - encoded.set(32, Bytes.wrap(BytesUtils.longToBytes(random, true))); - encoded.set(256, Bytes.wrap(sums)); - updateCrc(); - } - - public SumReplyMessage(MutableBytes encoded) { - super(encoded); - } - - @Override - public Bytes getEncoded() { - return encoded; - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.SUMS_REPLY; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + starttime - + " endtime=" - + this.endtime - + " netstatus=" - + xdagStats; - } - - public Bytes getSum() { - parse(); - return sums; - } - - @Override - public void parse() { - if (parsed) { - return; - } - - this.starttime = encoded.getLong(16, ByteOrder.LITTLE_ENDIAN); - this.endtime = encoded.getLong(24, ByteOrder.LITTLE_ENDIAN); - this.random = encoded.getLong(32, ByteOrder.LITTLE_ENDIAN); - BigInteger maxdifficulty = encoded.slice(80, 16).toUnsignedBigInteger(ByteOrder.LITTLE_ENDIAN); - long totalnblocks = encoded.getLong(104, ByteOrder.LITTLE_ENDIAN); - long totalnmains = encoded.getLong(120, ByteOrder.LITTLE_ENDIAN); - int totalnhosts = encoded.getInt(132, ByteOrder.LITTLE_ENDIAN); - long maintime = encoded.getLong(136, ByteOrder.LITTLE_ENDIAN); - xdagStats = new XdagStats(maxdifficulty, totalnblocks, totalnmains, totalnhosts, maintime); - - // test netdb - int length = 6; - // 80 是sizeof(xdag_stats) - MutableBytes netdb = MutableBytes.create(length * 32 - 80); - netdb.set(0, encoded.slice(144, length * 32 - 80)); - netDB = new NetDB(netdb.toArray()); - sums = MutableBytes.create(256); - sums.set(0, encoded.slice(256, 256)); - parsed = true; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/SumRequestMessage.java b/src/main/java/io/xdag/net/message/impl/SumRequestMessage.java deleted file mode 100644 index e805052d4..000000000 --- a/src/main/java/io/xdag/net/message/impl/SumRequestMessage.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.net.message.XdagMessageCodes.SUMS_REQUEST; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import lombok.EqualsAndHashCode; -import org.apache.commons.lang3.RandomUtils; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -@EqualsAndHashCode(callSuper = false) -public class SumRequestMessage extends AbstractMessage { - - public SumRequestMessage(long starttime, long endtime, XdagStats xdagStats, NetDB currentDB) { - super(SUMS_REQUEST, starttime, endtime, RandomUtils.nextLong(), xdagStats, currentDB); - updateCrc(); - } - - public SumRequestMessage(MutableBytes bytes) { - super(bytes); - } - - @Override - public Bytes getEncoded() { - return encoded; - } - - @Override - public Class getAnswerMessage() { - return SumReplyMessage.class; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.SUMS_REQUEST; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + starttime - + " endtime=" - + this.endtime - + " netstatus=" - + xdagStats; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/SyncBlockMessage.java b/src/main/java/io/xdag/net/message/impl/SyncBlockMessage.java deleted file mode 100644 index 0fdde1939..000000000 --- a/src/main/java/io/xdag/net/message/impl/SyncBlockMessage.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.xdag.net.message.impl; - -import io.xdag.core.Block; -import io.xdag.core.XdagBlock; -import static io.xdag.config.Constants.DNET_PKT_XDAG; -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.utils.BytesUtils; -import lombok.extern.slf4j.Slf4j; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -import java.util.zip.CRC32; - -@Slf4j -public class SyncBlockMessage extends Message { - private XdagBlock xdagBlock; - private Block block; - private int ttl; - - - /** - * 不处理crc - */ - public SyncBlockMessage(MutableBytes bytes) { - super(bytes); - } - - /** - * 处理crc 创建新的用于发送Block的message - */ - public SyncBlockMessage(Block block, int ttl) { - this.block = block; - this.ttl = ttl; - this.parsed = true; - encode(); - } - - /** - * 不处理crc - */ - public SyncBlockMessage(XdagBlock xdagBlock, int ttl) { - super(xdagBlock.getData().mutableCopy()); - this.xdagBlock = xdagBlock; - this.ttl = ttl; - } - - public Block getBlock() { - parse(); - return block; - } - - private void parse() { - if (parsed) { - return; - } - block = new Block(xdagBlock); - parsed = true; - } - - private void encode() { - this.encoded = this.block.getXdagBlock().getData().mutableCopy(); - // (1L << 31):Used to distinguish between newBlockMessage and syncBlockMessage. - long transportheader = ((long) ttl << 8) | DNET_PKT_XDAG | (512 << 16) | (1L << 31); - this.encoded.set(0, Bytes.wrap(BytesUtils.longToBytes(transportheader, true))); - - updateCrc(); - } - - public void updateCrc() { - CRC32 crc32 = new CRC32(); - crc32.update(encoded.toArray(), 0, 512); - this.encoded.set(4, Bytes.wrap(BytesUtils.intToBytes((int) crc32.getValue(), true))); - } - - public int getTtl() { - return ttl; - } - - public void setTtl(int ttl) { - this.ttl = ttl; - } - - @Override - public Bytes getEncoded() { - return encoded; - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.SYNC_BLOCK; - } - - @Override - public String toString() { - return "NewBlock Message:" + encoded.toHexString(); - } -} diff --git a/src/main/java/io/xdag/net/message/impl/SyncBlockRequestMessage.java b/src/main/java/io/xdag/net/message/impl/SyncBlockRequestMessage.java deleted file mode 100644 index 938b49424..000000000 --- a/src/main/java/io/xdag/net/message/impl/SyncBlockRequestMessage.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.xdag.net.message.impl; - -import io.xdag.core.XdagStats; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.utils.BytesUtils; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; -import org.apache.tuweni.bytes.MutableBytes; -import org.apache.tuweni.bytes.MutableBytes32; - -import java.math.BigInteger; -import java.nio.ByteOrder; - -import static io.xdag.config.Constants.DNET_PKT_XDAG; -import static io.xdag.core.XdagBlock.XDAG_BLOCK_SIZE; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_NONCE; - -public class SyncBlockRequestMessage extends AbstractMessage { - public SyncBlockRequestMessage(MutableBytes hash, XdagStats xdagStats, NetDB currentDB) { - super(XdagMessageCodes.SYNCBLOCK_REQUEST, 0, 0, Bytes32.wrap(hash), xdagStats,currentDB); - } - - public SyncBlockRequestMessage(MutableBytes hash) { - super(hash); - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public Bytes getEncoded() { - // TODO Auto-generated method stub - return encoded; - } - - @Override - public String toString() { - if (!parsed) { - parse(); - } - return "[" - + this.getCommand().name() - + " starttime=" - + starttime - + " endtime=" - + this.endtime - + " hash=" - + hash.toHexString() - + " netstatus=" - + xdagStats; - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.SYNCBLOCK_REQUEST; - } - - @Override - public void encode() { - parsed = true; - encoded = MutableBytes.create(512); - int ttl = 1; - long transportheader = (ttl << 8) | DNET_PKT_XDAG | (XDAG_BLOCK_SIZE << 16); - long type = (codes.asByte() << 4) | XDAG_FIELD_NONCE.asByte(); - - BigInteger diff = xdagStats.getDifficulty(); - BigInteger maxDiff = xdagStats.getMaxdifficulty(); - long nmain = xdagStats.getNmain(); - long totalMainNumber = Math.max(xdagStats.getTotalnmain(), nmain); - long nblocks = xdagStats.getNblocks(); - long totalBlockNumber = xdagStats.getTotalnblocks(); - - MutableBytes mutableBytes = MutableBytes.create(112); - long nhosts = currentDB.getIpList().size(); - long totalHosts = currentDB.getIpList().size(); - - mutableBytes.set(0, Bytes.wrap(BytesUtils.longToBytes(nhosts, true))); - mutableBytes.set(8, Bytes.wrap(BytesUtils.longToBytes(totalHosts, true))); - mutableBytes.set(16, Bytes.wrap(currentDB.getEncoded())); - -// // TODO:后续根据ip替换 -// String tmp = "04000000040000003ef4780100000000" + "7f000001611e7f000001b8227f0000015f767f000001d49d"; -// // net 相关 -// byte[] tmpbyte = Hex.decode(tmp); - - // field 0 and field1 - MutableBytes32 first = MutableBytes32.create(); - first.set(0, Bytes.wrap(BytesUtils.longToBytes(transportheader, true))); - first.set(8, Bytes.wrap(BytesUtils.longToBytes(type, true))); - first.set(16, Bytes.wrap(BytesUtils.longToBytes(starttime, true))); - first.set(24, Bytes.wrap(BytesUtils.longToBytes(endtime, true))); - - encoded.set(0, first); - encoded.set(32, hash.reverse()); - - // field2 diff and maxdiff - encoded.set(64, Bytes.wrap(BytesUtils.bigIntegerToBytes(diff, 16, true))); - encoded.set(80, Bytes.wrap(BytesUtils.bigIntegerToBytes(maxDiff, 16, true))); - - // field3 nblock totalblock main totalmain - encoded.set(96, Bytes.wrap(BytesUtils.longToBytes(nblocks, true))); - encoded.set(104, Bytes.wrap(BytesUtils.longToBytes(totalBlockNumber, true))); - encoded.set(112, Bytes.wrap(BytesUtils.longToBytes(nmain, true))); - encoded.set(120, Bytes.wrap(BytesUtils.longToBytes(totalMainNumber, true))); - encoded.set(128, Bytes.wrap(mutableBytes)); - updateCrc(); - } - - @Override - public void parse() { - if (parsed) { - return; - } - - this.starttime = encoded.getLong(16, ByteOrder.LITTLE_ENDIAN); - this.endtime = encoded.getLong(24, ByteOrder.LITTLE_ENDIAN); - BigInteger maxdifficulty = encoded.slice(80, 16).toUnsignedBigInteger(ByteOrder.LITTLE_ENDIAN); - long totalnblocks = encoded.getLong(104, ByteOrder.LITTLE_ENDIAN); - long totalnmains = encoded.getLong(120, ByteOrder.LITTLE_ENDIAN); - int totalnhosts = encoded.getInt(132, ByteOrder.LITTLE_ENDIAN); - long maintime = encoded.getLong(136, ByteOrder.LITTLE_ENDIAN); - xdagStats = new XdagStats(maxdifficulty, totalnblocks, totalnmains, totalnhosts, maintime); - MutableBytes32 hash = MutableBytes32.create(); - hash.set(0, encoded.slice(32, 24)); - this.hash = hash.copy(); - parsed = true; - } -} diff --git a/src/main/java/io/xdag/net/message/impl/Xdag03MessageFactory.java b/src/main/java/io/xdag/net/message/impl/Xdag03MessageFactory.java deleted file mode 100644 index b81922ea3..000000000 --- a/src/main/java/io/xdag/net/message/impl/Xdag03MessageFactory.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import static io.xdag.net.XdagVersion.V03; - -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageFactory; -import io.xdag.net.message.XdagMessageCodes; -import org.apache.tuweni.bytes.MutableBytes; - -public class Xdag03MessageFactory implements MessageFactory { - - @Override - public Message create(byte code, MutableBytes encoded) { - XdagMessageCodes receivedCommand = XdagMessageCodes.fromByte(code, V03); - - return switch (receivedCommand) { - case BLOCKS_REQUEST -> new BlocksRequestMessage(encoded); - case BLOCKS_REPLY -> new BlocksReplyMessage(encoded); - case SUMS_REQUEST -> new SumRequestMessage(encoded); - case SUMS_REPLY -> new SumReplyMessage(encoded); - case BLOCKEXT_REQUEST -> new BlockExtRequestMessage(encoded); - case BLOCKEXT_REPLY -> new BlockExtReplyMessage(encoded); - case BLOCK_REQUEST -> new BlockRequestMessage(encoded); - case NEW_BLOCK -> new NewBlockMessage(encoded); - case SYNC_BLOCK -> new SyncBlockMessage(encoded); - case SYNCBLOCK_REQUEST -> new SyncBlockRequestMessage(encoded); - default -> throw new IllegalArgumentException("No such message code" + code); - }; - } - -} diff --git a/src/main/java/io/xdag/mine/message/TaskShareMessage.java b/src/main/java/io/xdag/net/message/p2p/DisconnectMessage.java similarity index 58% rename from src/main/java/io/xdag/mine/message/TaskShareMessage.java rename to src/main/java/io/xdag/net/message/p2p/DisconnectMessage.java index 530d9ec3e..923573627 100644 --- a/src/main/java/io/xdag/mine/message/TaskShareMessage.java +++ b/src/main/java/io/xdag/net/message/p2p/DisconnectMessage.java @@ -21,46 +21,41 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.p2p; -package io.xdag.mine.message; - -import static io.xdag.net.message.XdagMessageCodes.TASK_SHARE; - -import io.xdag.core.XdagField; +import io.xdag.core.SimpleEncoder; import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; +import io.xdag.net.message.MessageCode; +import io.xdag.net.message.ReasonCode; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; +@Getter +public class DisconnectMessage extends Message { -public class TaskShareMessage extends Message { + private final ReasonCode reason; - private final XdagField xdagField; + public DisconnectMessage(ReasonCode reason) { + super(MessageCode.DISCONNECT, null); - public TaskShareMessage(MutableBytes encoded) { - super(encoded); - this.xdagField = new XdagField(encoded); - } + this.reason = reason; - @Override - public Bytes getEncoded() { - return xdagField.getData(); + SimpleEncoder enc = new SimpleEncoder(); + enc.writeByte(reason.toByte()); + this.body = enc.toBytes(); } - @Override - public Class getAnswerMessage() { - return null; - } + public DisconnectMessage(byte[] body) { + super(MessageCode.DISCONNECT, null); - @Override - public XdagMessageCodes getCommand() { - return TASK_SHARE; + SimpleDecoder dec = new SimpleDecoder(body); + this.reason = ReasonCode.of(dec.readByte()); + + this.body = body; } @Override public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); + return "DisconnectMessage [reason=" + reason + "]"; } -} +} \ No newline at end of file diff --git a/src/main/java/io/xdag/net/message/p2p/HandshakeMessage.java b/src/main/java/io/xdag/net/message/p2p/HandshakeMessage.java new file mode 100644 index 000000000..2c6b2ec07 --- /dev/null +++ b/src/main/java/io/xdag/net/message/p2p/HandshakeMessage.java @@ -0,0 +1,169 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import static io.xdag.utils.WalletUtils.toBase58; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.hyperledger.besu.crypto.KeyPair; +import org.hyperledger.besu.crypto.SECPPublicKey; +import org.hyperledger.besu.crypto.SECPSignature; + +import io.xdag.Network; +import io.xdag.config.Config; +import io.xdag.core.SimpleEncoder; +import io.xdag.crypto.Hash; +import io.xdag.crypto.Keys; +import io.xdag.crypto.Sign; +import io.xdag.net.Peer; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public abstract class HandshakeMessage extends Message { + + protected final Network network; + protected final short networkVersion; + + protected final String peerId; + protected final int port; + + protected final String clientId; + protected final String[] capabilities; + + protected final long latestBlockNumber; + + protected final byte[] secret; + protected final long timestamp; + protected final SECPSignature signature; + + protected SECPPublicKey publicKey; + + public HandshakeMessage(MessageCode code, Class responseMessageClass, + Network network, short networkVersion, String peerId, int port, + String clientId, String[] capabilities, long latestBlockNumber, + byte[] secret, KeyPair coinbase) { + super(code, responseMessageClass); + + this.network = network; + this.networkVersion = networkVersion; + this.peerId = peerId; + this.port = port; + this.clientId = clientId; + this.capabilities = capabilities; + this.latestBlockNumber = latestBlockNumber; + this.secret = secret; + this.timestamp = System.currentTimeMillis(); + this.publicKey = coinbase.getPublicKey(); + + SimpleEncoder enc = encodeBasicInfo(); + Bytes32 hash = Hash.sha256(Bytes.wrap(enc.toBytes())); + this.signature = Sign.SECP256K1.sign(hash, coinbase); + + enc.writeBytes(signature.encodedBytes().toArray()); + + this.body = enc.toBytes(); + } + + public HandshakeMessage(MessageCode code, Class responseMessageClass, byte[] body) { + super(code, responseMessageClass); + + SimpleDecoder dec = new SimpleDecoder(body); + this.network = Network.of(dec.readByte()); + this.networkVersion = dec.readShort(); + this.peerId = dec.readString(); + this.port = dec.readInt(); + this.clientId = dec.readString(); + List capabilities = new ArrayList<>(); + for (int i = 0, size = dec.readInt(); i < size; i++) { + capabilities.add(dec.readString()); + } + this.capabilities = capabilities.toArray(new String[0]); + this.latestBlockNumber = dec.readLong(); + this.secret = dec.readBytes(); + this.timestamp = dec.readLong(); + this.signature = Sign.SECP256K1.decodeSignature(Bytes.wrap(dec.readBytes())); + this.body = body; + } + + protected SimpleEncoder encodeBasicInfo() { + SimpleEncoder enc = new SimpleEncoder(); + + enc.writeByte(network.id()); + enc.writeShort(networkVersion); + enc.writeString(peerId); + enc.writeInt(port); + enc.writeString(clientId); + enc.writeInt(capabilities.length); + for (String capability : capabilities) { + enc.writeString(capability); + } + enc.writeLong(latestBlockNumber); + enc.writeBytes(secret); + enc.writeLong(timestamp); + + return enc; + } + + public boolean validate(Config config) { + SimpleEncoder enc = encodeBasicInfo(); + Bytes32 hash = Hash.sha256(Bytes.wrap(enc.toBytes())); + if(publicKey == null && signature !=null) { + publicKey = Sign.SECP256K1.recoverPublicKeyFromSignature(hash, signature).get(); + } + if (network == config.getNodeSpec().getNetwork() + && networkVersion == config.getNodeSpec().getNetworkVersion() + && peerId != null && peerId.length() <= 64 + && port > 0 && port <= 65535 + && clientId != null && clientId.length() < 128 + && latestBlockNumber >= 0 + && secret != null && secret.length == InitMessage.SECRET_LENGTH + && Math.abs(System.currentTimeMillis() - timestamp) <= config.getNodeSpec().getNetHandshakeExpiry() + && signature != null + && peerId.equals(toBase58(Keys.toBytesAddress(publicKey)))) { + + return Sign.SECP256K1.verify(hash, signature, publicKey); + } else { + return false; + } + } + + /** + * Constructs a Peer object from the handshake info. + * + * @param ip + * @return + */ + public Peer getPeer(String ip) { + return new Peer(network, networkVersion, peerId, ip, port, clientId, capabilities, latestBlockNumber); + } +} diff --git a/src/main/java/io/xdag/net/message/p2p/HelloMessage.java b/src/main/java/io/xdag/net/message/p2p/HelloMessage.java new file mode 100644 index 000000000..7e4e696f8 --- /dev/null +++ b/src/main/java/io/xdag/net/message/p2p/HelloMessage.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import java.util.Arrays; + +import org.hyperledger.besu.crypto.KeyPair; + +import io.xdag.Network; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; + +public class HelloMessage extends HandshakeMessage { + + public HelloMessage(Network network, short networkVersion, String peerId, int port, + String clientId, String[] capabilities, long latestBlockNumber, + byte[] secret, KeyPair coinbase) { + super(MessageCode.HANDSHAKE_HELLO, WorldMessage.class, network, networkVersion, peerId, port, clientId, + capabilities, latestBlockNumber, secret, coinbase); + } + + public HelloMessage(byte[] encoded) { + super(MessageCode.HANDSHAKE_HELLO, WorldMessage.class, encoded); + } + + @Override + public String toString() { + return "HelloMessage{" + + "peer=" + network + + ", networkVersion=" + networkVersion + + ", peerId='" + peerId + '\'' + + ", port=" + port + + ", clientId='" + clientId + '\'' + + ", capabilities=" + Arrays.toString(capabilities) + + ", latestBlockNumber=" + latestBlockNumber + + ", secret=" + BytesUtils.toHexString(secret) + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/io/xdag/net/message/p2p/InitMessage.java b/src/main/java/io/xdag/net/message/p2p/InitMessage.java new file mode 100644 index 000000000..0ee3d3a79 --- /dev/null +++ b/src/main/java/io/xdag/net/message/p2p/InitMessage.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import io.xdag.core.SimpleEncoder; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.BytesUtils; +import io.xdag.utils.SimpleDecoder; +import lombok.Getter; + +@Getter +public class InitMessage extends Message { + + public static final int SECRET_LENGTH = 32; + + private final byte[] secret; + private final long timestamp; + + public InitMessage(byte[] secret, long timestamp) { + super(MessageCode.HANDSHAKE_INIT, null); + + this.secret = secret; + this.timestamp = timestamp; + + SimpleEncoder enc = new SimpleEncoder(); + enc.writeBytes(secret); + enc.writeLong(timestamp); + + this.body = enc.toBytes(); + } + + public InitMessage(byte[] body) { + super(MessageCode.HANDSHAKE_INIT, null); + + SimpleDecoder dec = new SimpleDecoder(body); + this.secret = dec.readBytes(); + this.timestamp = dec.readLong(); + + this.body = body; + } + + public boolean validate() { + return secret != null && secret.length == SECRET_LENGTH && timestamp > 0; + } + + @Override + public String toString() { + return "InitMessage{" + + "secret=" + BytesUtils.toHexString(secret) + + ", timestamp=" + timestamp + + '}'; + } +} diff --git a/src/main/java/io/xdag/net/message/impl/BlockExtReplyMessage.java b/src/main/java/io/xdag/net/message/p2p/PingMessage.java similarity index 60% rename from src/main/java/io/xdag/net/message/impl/BlockExtReplyMessage.java rename to src/main/java/io/xdag/net/message/p2p/PingMessage.java index 00c4ea9a5..b9686f58a 100644 --- a/src/main/java/io/xdag/net/message/impl/BlockExtReplyMessage.java +++ b/src/main/java/io/xdag/net/message/p2p/PingMessage.java @@ -1,61 +1,58 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.message.impl; - -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; - -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.MutableBytes; - -public class BlockExtReplyMessage extends Message { - - public BlockExtReplyMessage(MutableBytes bytes) { - super(bytes); - } - - @Override - public Class getAnswerMessage() { - return null; - } - - @Override - public Bytes getEncoded() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).toString(); - } - - @Override - public XdagMessageCodes getCommand() { - return XdagMessageCodes.BLOCKEXT_REPLY; - } -} +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import io.xdag.core.SimpleEncoder; +import io.xdag.net.message.Message; +import io.xdag.net.message.MessageCode; +import io.xdag.utils.SimpleDecoder; + +public class PingMessage extends Message { + + private final long timestamp; + + public PingMessage() { + super(MessageCode.PING, PongMessage.class); + + this.timestamp = System.currentTimeMillis(); + + SimpleEncoder enc = new SimpleEncoder(); + enc.writeLong(timestamp); + this.body = enc.toBytes(); + } + + public PingMessage(byte[] body) { + super(MessageCode.PING, PongMessage.class); + + SimpleDecoder dec = new SimpleDecoder(body); + this.timestamp = dec.readLong(); + + this.body = body; + } + + @Override + public String toString() { + return "PingMessage [timestamp=" + timestamp + "]"; + } +} diff --git a/src/main/java/io/xdag/mine/manager/MinerManager.java b/src/main/java/io/xdag/net/message/p2p/PongMessage.java similarity index 60% rename from src/main/java/io/xdag/mine/manager/MinerManager.java rename to src/main/java/io/xdag/net/message/p2p/PongMessage.java index 39129e8ca..ca87e38f0 100644 --- a/src/main/java/io/xdag/mine/manager/MinerManager.java +++ b/src/main/java/io/xdag/net/message/p2p/PongMessage.java @@ -21,39 +21,38 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.p2p; -package io.xdag.mine.manager; - -import io.xdag.consensus.PoW; -import io.xdag.consensus.Task; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.miner.Miner; +import io.xdag.core.SimpleEncoder; import io.xdag.net.message.Message; -import java.net.InetSocketAddress; -import java.util.Map; -import org.apache.tuweni.bytes.Bytes; - -public interface MinerManager { - - Map getActivateMiners(); - - void onNewShare(MinerChannel channel, Message msg); +import io.xdag.net.message.MessageCode; +import io.xdag.utils.SimpleDecoder; - void setPoW(PoW pow); +public class PongMessage extends Message { - void start(); + private final long timestamp; - void addActivateChannel(MinerChannel channel); + public PongMessage() { + super(MessageCode.PONG, null); - void stop(); + this.timestamp = System.currentTimeMillis(); - MinerChannel getChannelByHost(InetSocketAddress host); + SimpleEncoder enc = new SimpleEncoder(); + enc.writeLong(timestamp); + this.body = enc.toBytes(); + } - Map getActivateMinerChannels(); + public PongMessage(byte[] body) { + super(MessageCode.PONG, null); - void removeUnactivateChannel(MinerChannel channel); + SimpleDecoder dec = new SimpleDecoder(body); + this.timestamp = dec.readLong(); - void updateTask(Task task); + this.body = body; + } - void addActiveMiner(Miner miner); + @Override + public String toString() { + return "PongMessage [timestamp=" + timestamp + "]"; + } } diff --git a/src/main/java/io/xdag/net/message/p2p/WorldMessage.java b/src/main/java/io/xdag/net/message/p2p/WorldMessage.java new file mode 100644 index 000000000..1211445b4 --- /dev/null +++ b/src/main/java/io/xdag/net/message/p2p/WorldMessage.java @@ -0,0 +1,61 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import java.util.Arrays; + +import org.apache.tuweni.bytes.Bytes; +import org.hyperledger.besu.crypto.KeyPair; + +import io.xdag.Network; +import io.xdag.net.message.MessageCode; + +public class WorldMessage extends HandshakeMessage { + + public WorldMessage(Network network, short networkVersion, String peerId, int port, + String clientId, String[] capabilities, long latestBlockNumber, + byte[] secret, KeyPair coinbase) { + super(MessageCode.HANDSHAKE_WORLD, null, network, networkVersion, peerId, port, clientId, + capabilities, latestBlockNumber, secret, coinbase); + } + + public WorldMessage(byte[] encoded) { + super(MessageCode.HANDSHAKE_WORLD, null, encoded); + } + + @Override + public String toString() { + return "WorldMessage{" + + "network=" + network + + ", networkVersion=" + networkVersion + + ", peerId='" + peerId + '\'' + + ", port=" + port + + ", clientId='" + clientId + '\'' + + ", capabilities=" + Arrays.toString(capabilities) + + ", latestBlockNumber=" + latestBlockNumber + + ", secret=" + Bytes.wrap(secret).toHexString() + + ", timestamp=" + timestamp + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/io/xdag/net/node/Node.java b/src/main/java/io/xdag/net/node/Node.java index 60332ccdc..447dfbf38 100644 --- a/src/main/java/io/xdag/net/node/Node.java +++ b/src/main/java/io/xdag/net/node/Node.java @@ -24,57 +24,46 @@ package io.xdag.net.node; -import io.xdag.utils.BytesUtils; -import java.net.InetAddress; import java.net.InetSocketAddress; import lombok.Getter; -import org.apache.commons.codec.binary.Hex; -import org.apache.commons.lang3.RandomUtils; +@Getter public class Node { - @Getter - private final String host; + private final InetSocketAddress address; - @Getter - private final int port; - @Getter - private final NodeStat stat = new NodeStat(); - @Getter - private byte[] id; + public Node(InetSocketAddress address) { + this.address = address; + } - public Node(String host, int port) { - this.host = host; - this.port = port; - this.id = BytesUtils.longToBytes(RandomUtils.nextLong(), true); + public Node(String ip, int port) { + this(new InetSocketAddress(ip, port)); } - public Node(byte[] id, String host, int port) { - this.id = id; - this.host = host; - this.port = port; + public String getIp() { + return address.getAddress().getHostAddress(); } - public Node(InetAddress address, int port) { - this.host = address.getHostAddress(); - this.port = port; + public int getPort() { + return address.getPort(); } - public String getHexId() { - return Hex.encodeHexString(id); + public InetSocketAddress toAddress() { + return this.address; } - public InetSocketAddress getAddress() { - return new InetSocketAddress(this.getHost(), this.getPort()); + @Override + public int hashCode() { + return address.hashCode(); } @Override public boolean equals(Object o) { - return o instanceof Node && getAddress().equals(((Node) o).getAddress()); + return o instanceof Node && address.equals(((Node) o).toAddress()); } @Override - public int hashCode() { - return getAddress().hashCode(); + public String toString() { + return getIp() + ":" + getPort(); } } diff --git a/src/main/java/io/xdag/net/node/NodeManager.java b/src/main/java/io/xdag/net/node/NodeManager.java index 6d97c1d3c..18ff7d418 100644 --- a/src/main/java/io/xdag/net/node/NodeManager.java +++ b/src/main/java/io/xdag/net/node/NodeManager.java @@ -24,28 +24,20 @@ package io.xdag.net.node; -import static io.xdag.net.libp2p.Libp2pUtils.discoveryPeerToDailId; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.net.Channel; -import io.xdag.net.XdagClient; -import io.xdag.net.handler.XdagChannelInitializer; -import io.xdag.net.libp2p.Libp2pNetwork; -import io.xdag.net.libp2p.discovery.DiscoveryPeer; -import io.xdag.net.manager.NetDBManager; -import io.xdag.net.manager.XdagChannelManager; -import io.xdag.net.message.NetDB; +import io.xdag.net.PeerClient; +import io.xdag.net.XdagChannelInitializer; +import io.xdag.net.NetDBManager; +import io.xdag.net.ChannelManager; +import io.xdag.net.NetDB; import java.net.InetSocketAddress; import java.util.Collection; import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ScheduledExecutorService; @@ -77,17 +69,13 @@ public class NodeManager { */ private final ScheduledExecutorService exec; private final Kernel kernel; - private final XdagClient client; - private final XdagChannelManager channelMgr; + private final PeerClient client; + private final ChannelManager channelMgr; private final NetDBManager netDBManager; private final Config config; - private final Libp2pNetwork libp2pNetwork; - private final Node myself; private volatile boolean isRunning; private ScheduledFuture connectFuture; private ScheduledFuture fetchFuture; - private ScheduledFuture connectlibp2PFuture; - private Set hadConnected; public NodeManager(Kernel kernel) { this.kernel = kernel; @@ -96,9 +84,6 @@ public NodeManager(Kernel kernel) { this.exec = new ScheduledThreadPoolExecutor(1, factory); this.config = kernel.getConfig(); this.netDBManager = kernel.getNetDBMgr(); - libp2pNetwork = kernel.getLibp2pNetwork(); - myself = new Node(kernel.getConfig().getNodeSpec().getNodeIp(), - kernel.getConfig().getNodeSpec().getLibp2pPort()); } /** @@ -114,8 +99,6 @@ public synchronized void start() { // every 100 seconds, delayed by 5 seconds (public IP lookup) fetchFuture = exec.scheduleAtFixedRate(this::doFetch, 5, 100, TimeUnit.SECONDS); - connectlibp2PFuture = exec.scheduleAtFixedRate(this::doConnectlibp2p, 10, 10, TimeUnit.SECONDS); - hadConnected = new HashSet<>(); isRunning = true; log.debug("Node manager started"); } @@ -125,7 +108,6 @@ public synchronized void stop() { if (isRunning) { connectFuture.cancel(true); fetchFuture.cancel(false); - connectlibp2PFuture.cancel(true); isRunning = false; exec.shutdown(); log.debug("Node manager stop..."); @@ -137,7 +119,7 @@ public int queueSize() { } public void addNodes(Collection nodes) { - if (nodes == null || nodes.size() == 0) { + if (nodes == null || nodes.isEmpty()) { return; } for (Node node : nodes) { @@ -160,7 +142,7 @@ public void addNode(Node node) { * from net update seed nodes */ protected void doFetch() { - log.debug("Do fetch"); + log.debug("Do fetch node size:{}", deque.size()); if (config.getNodeSpec().enableRefresh()) { netDBManager.refresh(); } @@ -168,8 +150,6 @@ protected void doFetch() { addNodes(getSeedNodes(netDBManager.getWhiteDB())); // 从netdb获取新节点 addNodes(getSeedNodes(netDBManager.getNetDB())); - - log.debug("node size:" + deque.size()); } public Set getSeedNodes(NetDB netDB) { @@ -181,7 +161,6 @@ public Set getSeedNodes(NetDB netDB) { } public void doConnect() { - Set activeAddress = channelMgr.getActiveAddresses(); Node node; while ((node = deque.pollFirst()) != null && channelMgr.size() < config.getNodeSpec().getMaxConnections()) { @@ -189,12 +168,11 @@ public void doConnect() { long now = System.currentTimeMillis(); if (!client.getNode().equals(node) - && !(Objects.equals(node.getHost(), client.getNode().getHost()) - && node.getPort() == client.getNode().getPort()) + && !node.equals(client.getNode()) && !activeAddress.contains(node.getAddress()) && (lastCon == null || lastCon + RECONNECT_WAIT < now)) { XdagChannelInitializer initializer = new XdagChannelInitializer(kernel, false, node); - client.connect(node.getHost(), node.getPort(), initializer); + client.connect(node, initializer); lastConnect.put(node, now); break; } @@ -203,40 +181,12 @@ public void doConnect() { } public void doConnect(String ip, int port) { + Set activeAddresses = channelMgr.getActiveAddresses(); Node remotenode = new Node(ip, port); - if (!client.getNode().equals(remotenode) && !channelMgr.containsNode(remotenode)) { + if (!client.getNode().equals(remotenode) && !activeAddresses.contains(remotenode.toAddress())) { XdagChannelInitializer initializer = new XdagChannelInitializer(kernel, false, remotenode); - client.connect(ip, port, initializer); - } - } - - //todo:发现之后的节点只能自动连接一次 - public void doConnectlibp2p() { - Set activeAddress = channelMgr.getActiveAddresses(); - List discoveryPeerList = - libp2pNetwork.getDiscV5Service().streamKnownPeers().toList(); - for (DiscoveryPeer p : discoveryPeerList) { - Node node = new Node(p.getNodeAddress().getHostName(), p.getNodeAddress().getPort()); - if (!myself.equals(node) && !activeAddress.contains(p.getNodeAddress()) && !hadConnected.contains(node)) { - kernel.getLibp2pNetwork().dail(discoveryPeerToDailId(p)); - hadConnected.add(node); - } - } - } - - public Map getActiveNode() { - Map nodes = new HashMap<>(); - List activeAddress = channelMgr.getActiveChannels(); - for (Channel address : activeAddress) { - Node node = address.getNode(); - Long time = lastConnect.getIfPresent(node); - if (time == null) { - // 尝试在channel管理器中查询 - time = channelMgr.getChannelLastConnect().getIfPresent(node.getAddress()); - } - nodes.put(node, time); + client.connect(new Node(ip, port), initializer); } - return nodes; } } diff --git a/src/main/java/io/xdag/rpc/Web3Impl.java b/src/main/java/io/xdag/rpc/Web3Impl.java index 49aa0bf4a..65979d892 100644 --- a/src/main/java/io/xdag/rpc/Web3Impl.java +++ b/src/main/java/io/xdag/rpc/Web3Impl.java @@ -140,15 +140,6 @@ public Object xdag_netConnectionList() throws Exception { return web3XdagModule.xdag_netConnectionList(); } - @Override - public Object xdag_updatePoolConfig(ConfigDTO configDTO,String passphrase) throws Exception { - return web3XdagModule.xdag_updatePoolConfig(configDTO,passphrase); - } - - @Override - public Object xdag_getPoolWorkers() throws Exception { - return web3XdagModule.xdag_getPoolWorkers(); - } @Override public String xdag_getMaxXferBalance() throws Exception { return web3XdagModule.xdag_getMaxXferBalance(); diff --git a/src/main/java/io/xdag/rpc/dto/NetConnDTO.java b/src/main/java/io/xdag/rpc/dto/NetConnDTO.java index d670468c8..a3e56f7e8 100644 --- a/src/main/java/io/xdag/rpc/dto/NetConnDTO.java +++ b/src/main/java/io/xdag/rpc/dto/NetConnDTO.java @@ -23,7 +23,6 @@ */ package io.xdag.rpc.dto; -import java.net.InetSocketAddress; import lombok.Builder; import lombok.Data; @@ -31,9 +30,6 @@ @Builder public class NetConnDTO { - InetSocketAddress nodeAddress; - long connectTime; - long inBound; - long outBound; + String info; } diff --git a/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModule.java b/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModule.java index ba80deaca..eb0611644 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModule.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModule.java @@ -118,9 +118,5 @@ default BlockResultDTO xdag_getBlockByHash(String blockHash, int page, int pageS Object xdag_netConnectionList() throws Exception; - Object xdag_updatePoolConfig(ConfigDTO args, String passphrase) throws Exception; - - Object xdag_getPoolWorkers() throws Exception; - String xdag_getMaxXferBalance() throws Exception; } diff --git a/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModuleImpl.java b/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModuleImpl.java index a631b6415..5d4eb0516 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/Web3XdagModuleImpl.java @@ -32,15 +32,10 @@ import io.xdag.config.MainnetConfig; import io.xdag.config.TestnetConfig; import io.xdag.config.spec.NodeSpec; -import io.xdag.config.spec.PoolSpec; import io.xdag.core.*; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.miner.Miner; -import io.xdag.mine.miner.MinerCalculate; -import io.xdag.net.node.Node; +import io.xdag.net.Channel; import io.xdag.rpc.dto.ConfigDTO; import io.xdag.rpc.dto.NetConnDTO; -import io.xdag.rpc.dto.PoolWorkerDTO; import io.xdag.rpc.dto.StatusDTO; import io.xdag.utils.BasicUtils; import lombok.extern.slf4j.Slf4j; @@ -48,13 +43,11 @@ import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.bytes.MutableBytes32; -import java.net.InetSocketAddress; -import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.Objects; import static io.xdag.config.Constants.CLIENT_VERSION; +import static io.xdag.crypto.Keys.toBytesAddress; import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; import static io.xdag.utils.BasicUtils.*; import static io.xdag.utils.WalletUtils.*; @@ -117,7 +110,7 @@ public Object xdag_syncing() { @Override public String xdag_coinbase() { - return toBase58(hash2byte(kernel.getPoolMiner().getAddressHash().mutableCopy())); + return toBase58(toBytesAddress(kernel.getCoinbase())); } @Override @@ -185,22 +178,22 @@ public Object xdag_netType() { @Override public Object xdag_poolConfig() { - PoolSpec poolSpec = kernel.getConfig().getPoolSpec(); +// PoolSpec poolSpec = kernel.getConfig().getPoolSpec(); NodeSpec nodeSpec = kernel.getConfig().getNodeSpec(); ConfigDTO.ConfigDTOBuilder configDTOBuilder = ConfigDTO.builder(); - configDTOBuilder.poolIp(poolSpec.getPoolIp()); - configDTOBuilder.poolPort(poolSpec.getPoolPort()); +// configDTOBuilder.poolIp(poolSpec.getPoolIp()); +// configDTOBuilder.poolPort(poolSpec.getPoolPort()); configDTOBuilder.nodeIp(nodeSpec.getNodeIp()); configDTOBuilder.nodePort(nodeSpec.getNodePort()); - configDTOBuilder.globalMinerLimit(poolSpec.getGlobalMinerLimit()); - configDTOBuilder.maxConnectMinerPerIp(poolSpec.getMaxConnectPerIp()); - configDTOBuilder.maxMinerPerAccount(poolSpec.getMaxMinerPerAccount()); +// configDTOBuilder.globalMinerLimit(poolSpec.getGlobalMinerLimit()); +// configDTOBuilder.maxConnectMinerPerIp(poolSpec.getMaxConnectPerIp()); +// configDTOBuilder.maxMinerPerAccount(poolSpec.getMaxMinerPerAccount()); - configDTOBuilder.poolFundRation(Double.toString(kernel.getAwardManager().getPoolConfig().getFundRation() * 100)); - configDTOBuilder.poolFeeRation(Double.toString(kernel.getAwardManager().getPoolConfig().getPoolRation() * 100)); - configDTOBuilder.poolDirectRation(Double.toString(kernel.getAwardManager().getPoolConfig().getDirectRation() * 100)); - configDTOBuilder.poolRewardRation(Double.toString(kernel.getAwardManager().getPoolConfig().getMinerRewardRation() * 100)); +// configDTOBuilder.poolFundRation(Double.toString(kernel.getAwardManager().getPoolConfig().getFundRation() * 100)); +// configDTOBuilder.poolFeeRation(Double.toString(kernel.getAwardManager().getPoolConfig().getPoolRation() * 100)); +// configDTOBuilder.poolDirectRation(Double.toString(kernel.getAwardManager().getPoolConfig().getDirectRation() * 100)); +// configDTOBuilder.poolRewardRation(Double.toString(kernel.getAwardManager().getPoolConfig().getMinerRewardRation() * 100)); return configDTOBuilder.build(); } @@ -208,13 +201,9 @@ public Object xdag_poolConfig() { public Object xdag_netConnectionList() { List netConnDTOList = Lists.newArrayList(); NetConnDTO.NetConnDTOBuilder netConnDTOBuilder = NetConnDTO.builder(); - Map map = kernel.getNodeMgr().getActiveNode(); - for (Map.Entry entry : map.entrySet()) { - Node node = entry.getKey(); - netConnDTOBuilder.connectTime(map.get(node) == null ? 0 : map.get(node)) // use default "0" - .inBound(node.getStat().Inbound.get()) - .outBound(node.getStat().Outbound.get()) - .nodeAddress(node.getAddress()); + List channelList = kernel.getChannelMgr().getActiveChannels(); + for (Channel channel : channelList) { + netConnDTOBuilder.info(channel.toString()); netConnDTOList.add(netConnDTOBuilder.build()); } @@ -229,69 +218,32 @@ static class SyncingResult { } - @Override - public Object xdag_updatePoolConfig(ConfigDTO configDTO, String passphrase) { - try { - //unlock - if (checkPassword(passphrase)) { - double poolFeeRation = configDTO.getPoolFeeRation() != null ? - Double.parseDouble(configDTO.getPoolFeeRation()) : kernel.getConfig().getPoolSpec().getPoolRation(); - double poolRewardRation = configDTO.getPoolRewardRation() != null ? - Double.parseDouble(configDTO.getPoolRewardRation()) : kernel.getConfig().getPoolSpec().getRewardRation(); - double poolDirectRation = configDTO.getPoolDirectRation() != null ? - Double.parseDouble(configDTO.getPoolDirectRation()) : kernel.getConfig().getPoolSpec().getDirectRation(); - double poolFundRation = configDTO.getPoolFundRation() != null ? - Double.parseDouble(configDTO.getPoolFundRation()) : kernel.getConfig().getPoolSpec().getFundRation(); - kernel.getAwardManager().updatePoolConfig(poolFeeRation, poolRewardRation, poolDirectRation, poolFundRation); - } - } catch (NumberFormatException e) { - return "Error"; - } - return "Success"; - } - - @Override - public Object xdag_getPoolWorkers() { - List poolWorkerDTOList = Lists.newArrayList(); - PoolWorkerDTO.PoolWorkerDTOBuilder poolWorkerDTOBuilder = PoolWorkerDTO.builder(); - Collection miners = kernel.getMinerManager().getActivateMiners().values(); - PoolWorkerDTO poolWorker = getPoolWorkerDTO(poolWorkerDTOBuilder, kernel.getPoolMiner()); - poolWorker.setStatus("fee"); - poolWorkerDTOList.add(poolWorker); - for (Miner miner : miners) { - poolWorkerDTOList.add(getPoolWorkerDTO(poolWorkerDTOBuilder,miner)); - } - return poolWorkerDTOList; - } +// @Override +// public Object xdag_updatePoolConfig(ConfigDTO configDTO, String passphrase) { +// try { +// //unlock +// if (checkPassword(passphrase)) { +// double poolFeeRation = configDTO.getPoolFeeRation() != null ? +// Double.parseDouble(configDTO.getPoolFeeRation()) : kernel.getConfig().getPoolSpec().getPoolRation(); +// double poolRewardRation = configDTO.getPoolRewardRation() != null ? +// Double.parseDouble(configDTO.getPoolRewardRation()) : kernel.getConfig().getPoolSpec().getRewardRation(); +// double poolDirectRation = configDTO.getPoolDirectRation() != null ? +// Double.parseDouble(configDTO.getPoolDirectRation()) : kernel.getConfig().getPoolSpec().getDirectRation(); +// double poolFundRation = configDTO.getPoolFundRation() != null ? +// Double.parseDouble(configDTO.getPoolFundRation()) : kernel.getConfig().getPoolSpec().getFundRation(); +// kernel.getAwardManager().updatePoolConfig(poolFeeRation, poolRewardRation, poolDirectRation, poolFundRation); +// } +// } catch (NumberFormatException e) { +// return "Error"; +// } +// return "Success"; +// } @Override public String xdag_getMaxXferBalance() { return xdagModule.getMaxXferBalance(); } - private PoolWorkerDTO getPoolWorkerDTO(PoolWorkerDTO.PoolWorkerDTOBuilder poolWorkerDTOBuilder,Miner miner){ - poolWorkerDTOBuilder.address(toBase58(miner.getAddressHashByte())) - .status(miner.getMinerStates().toString()) - .unpaidShares(MinerCalculate.calculateUnpaidShares(miner)) - .hashrate(BasicUtils.xdag_log_difficulty2hashrate(miner.getMeanLogDiff())) - .workers(getWorkers(miner)); - return poolWorkerDTOBuilder.build(); - } - private List getWorkers(Miner miner) { - List workersList = Lists.newArrayList(); - PoolWorkerDTO.Worker.WorkerBuilder workerBuilder = PoolWorkerDTO.Worker.builder(); - Map channels = miner.getChannels(); - for (Map.Entry channel : channels.entrySet()) { - workerBuilder.address(channel.getKey()).inBound(channel.getValue().getInBound().get()) - .outBound(channel.getValue().getOutBound().get()) - .unpaidShares(MinerCalculate.calculateUnpaidShares(channel.getValue())) - .name(channel.getValue().getWorkerName()) - .hashrate(BasicUtils.xdag_log_difficulty2hashrate(channel.getValue().getMeanLogDiff())); - workersList.add(workerBuilder.build()); - } - return workersList; - } - private boolean checkPassword(String passphrase) { Wallet wallet = new Wallet(kernel.getConfig()); return wallet.unlock(passphrase); diff --git a/src/main/java/io/xdag/utils/exception/UnreachableException.java b/src/main/java/io/xdag/utils/exception/UnreachableException.java new file mode 100644 index 000000000..ce86d2c3a --- /dev/null +++ b/src/main/java/io/xdag/utils/exception/UnreachableException.java @@ -0,0 +1,50 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.utils.exception; + +public class UnreachableException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public UnreachableException() { + super("Should never reach here"); + } + + public UnreachableException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public UnreachableException(String message, Throwable cause) { + super(message, cause); + } + + public UnreachableException(String message) { + super(message); + } + + public UnreachableException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/resources/dnet_keys.bin b/src/main/resources/dnet_keys.bin deleted file mode 100644 index 979093ba2..000000000 Binary files a/src/main/resources/dnet_keys.bin and /dev/null differ diff --git a/src/main/resources/rpc_modules.conf b/src/main/resources/rpc_modules.conf index 1252ee906..206c470ef 100644 --- a/src/main/resources/rpc_modules.conf +++ b/src/main/resources/rpc_modules.conf @@ -6,7 +6,7 @@ rpc { enabled = true bind_address = localhost hosts = [] - port = 4444 + port = 10001 # A value greater than zero sets the socket value in milliseconds. Node attempts to gently close all # TCP/IP connections with proper half close semantics, so a linger timeout should not be required and # thus the default is -1. @@ -15,7 +15,7 @@ rpc { ws { enabled = true bind_address = localhost - port = 4445 + port = 10002 } } } diff --git a/src/main/resources/xdag-devnet.conf b/src/main/resources/xdag-devnet.conf index 475f1c8e5..f18cac546 100644 --- a/src/main/resources/xdag-devnet.conf +++ b/src/main/resources/xdag-devnet.conf @@ -3,45 +3,22 @@ admin.telnet.ip = 127.0.0.1 admin.telnet.port = 6001 admin.telnet.password = root -# Pool Config -pool.ip = 127.0.0.1 -pool.port = 7001 -pool.tag = XdagJ - -# Pool-Reward Config -pool.poolRation = 5 -pool.rewardRation = 5 -pool.fundRation = 5 -pool.directRation = 5 -pool.fundAddress = FQglVQtb60vQv2DOWEUL7yh3smtj7g1s - # Node config node.ip = 127.0.0.1 node.port = 8001 +node.tag = xdagj-node-1 node.maxInboundConnectionsPerIp = 8 node.whiteIPs = ["127.0.0.1:8001","127.0.0.1:8002"] node.generate.block.enable = true # Node transaction history config -node.transaction.history.enable = true - -# Node libp2p Config -node.libp2p.port = 9001 -node.libp2p.isbootnode = true -node.libp2p.privkey = 0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5 -node.libp2p.bootnode = ["enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR"] +node.transaction.history.enable = false # Node RPC Config -rpc.enabled = true +rpc.enabled = false rpc.http.host = 127.0.0.1 rpc.http.port = 10001 rpc.ws.port = 10002 -# Miner Config -miner.globalMinerLimit = 8192 -miner.globalMinerChannelLimit = 8192 -miner.maxConnectPerIp = 256 -miner.maxMinerPerAccount = 256 - # Randomx Config randomx.flags.fullmem = false \ No newline at end of file diff --git a/src/main/resources/xdag-mainnet.conf b/src/main/resources/xdag-mainnet.conf index 3a2e75293..508e8d8f3 100644 --- a/src/main/resources/xdag-mainnet.conf +++ b/src/main/resources/xdag-mainnet.conf @@ -8,13 +8,6 @@ pool.ip = 127.0.0.1 pool.port = 7001 pool.tag = XdagJ -# Pool-Reward Config -pool.poolRation = 5 -pool.rewardRation = 5 -pool.fundRation = 5 -pool.directRation = 5 -pool.fundAddress = FQglVQtb60vQv2DOWEUL7yh3smtj7g1s - # Node config node.ip = 127.0.0.1 node.port = 8001 @@ -26,12 +19,6 @@ node.generate.block.enable = true node.transaction.history.enable = true node.transaction.history.pageSizeLimit = 500 -# Node libp2p Config -node.libp2p.port = 9001 -node.libp2p.isbootnode = true -node.libp2p.privkey = 0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5 -node.libp2p.bootnode = ["enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR"] - # Node RPC Config rpc.enabled = true rpc.http.host = 127.0.0.1 diff --git a/src/main/resources/xdag-testnet.conf b/src/main/resources/xdag-testnet.conf index 58fd9a45f..e3fb48854 100644 --- a/src/main/resources/xdag-testnet.conf +++ b/src/main/resources/xdag-testnet.conf @@ -8,13 +8,6 @@ pool.ip = 127.0.0.1 pool.port = 7001 pool.tag = XdagJ -# Pool-Reward Config -pool.poolRation = 5 -pool.rewardRation = 5 -pool.fundRation = 5 -pool.directRation = 5 -pool.fundAddress = FQglVQtb60vQv2DOWEUL7yh3smtj7g1s - # Node config node.ip = 127.0.0.1 node.port = 8001 @@ -25,23 +18,11 @@ node.generate.block.enable = true # Node transaction history config node.transaction.history.enable = true -# Node libp2p Config -node.libp2p.port = 9001 -node.libp2p.isbootnode = true -node.libp2p.privkey = 0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5 -node.libp2p.bootnode = ["enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR"] - # Node RPC Config rpc.enabled = true rpc.http.host = 127.0.0.1 rpc.http.port = 10001 rpc.ws.port = 10002 -# Miner Config -miner.globalMinerLimit = 8192 -miner.globalMinerChannelLimit = 8192 -miner.maxConnectPerIp = 256 -miner.maxMinerPerAccount = 256 - # Randomx Config randomx.flags.fullmem = false \ No newline at end of file diff --git a/src/test/java/io/xdag/cli/CommandsTest.java b/src/test/java/io/xdag/cli/CommandsTest.java index 3bab25a17..9abbab0a3 100644 --- a/src/test/java/io/xdag/cli/CommandsTest.java +++ b/src/test/java/io/xdag/cli/CommandsTest.java @@ -28,17 +28,14 @@ import static junit.framework.TestCase.assertEquals; import java.math.BigInteger; -import java.net.InetSocketAddress; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.List; -import java.util.Map; import java.util.TimeZone; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.FastDateFormat; -import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.apache.tuweni.units.bigints.UInt64; import org.hyperledger.besu.crypto.KeyPair; @@ -47,7 +44,6 @@ import org.junit.Test; import org.mockito.Mockito; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import io.xdag.Kernel; import io.xdag.Wallet; @@ -70,11 +66,8 @@ import io.xdag.crypto.Sign; import io.xdag.db.AddressStore; import io.xdag.db.BlockStore; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.manager.MinerManager; -import io.xdag.mine.miner.Miner; -import io.xdag.net.manager.NetDBManager; -import io.xdag.net.message.NetDB; +import io.xdag.net.NetDBManager; +import io.xdag.net.NetDB; import io.xdag.utils.BasicUtils; import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; @@ -303,23 +296,6 @@ public void testKeygen() assertEquals("Key 1 generated and set as default,now key size is:2", str); } - @Test - public void testMiners() { - Miner mockPoolMiner = new Miner(BytesUtils.arrayToByte32(Keys.toBytesAddress(keyPair_1.getPublicKey()))); - Miner mockMiner2 = new Miner(BytesUtils.arrayToByte32(Keys.toBytesAddress(keyPair_2.getPublicKey()))); - Map mockActivateMiners = Maps.newHashMap(); - mockActivateMiners.put(mockPoolMiner.getAddressHash(), mockPoolMiner); - mockActivateMiners.put(mockMiner2.getAddressHash(), mockMiner2); - - MinerManager mockMinerManager = Mockito.mock(MinerManager.class); - Mockito.when(kernel.getPoolMiner()).thenReturn(mockPoolMiner); - Mockito.when(kernel.getMinerManager()).thenReturn(mockMinerManager); - Mockito.when(mockMinerManager.getActivateMiners()).thenReturn(mockActivateMiners); - - String str = commands.miners(); - assertEquals("fee:PbwjuQP3y9F3ZnbbWUvue4zpgkQv3DHas\n", str); - } - @Test public void testState() { Mockito.when(kernel.getXdagState()).thenReturn(XdagState.INIT); @@ -327,25 +303,6 @@ public void testState() { assertEquals("Pool Initializing....", str); } - @Test - public void testDisConnectMinerChannel() { - Map mockMinerChannels = Maps.newHashMap(); - MinerChannel mc = Mockito.mock(MinerChannel.class); - InetSocketAddress host = new InetSocketAddress("127.0.0.1", 10001); - - MinerManager mockMinerManager = Mockito.mock(MinerManager.class); - Mockito.when(mockMinerManager.getActivateMinerChannels()).thenReturn(mockMinerChannels); - Mockito.when(kernel.getMinerManager()).thenReturn(mockMinerManager); - Mockito.when(mockMinerManager.getChannelByHost(host)).thenReturn(mc); - - String str = commands.disConnectMinerChannel("127.0.0.1:10001"); - assertEquals("disconnect a channel:127.0.0.1:10001", str); - str = commands.disConnectMinerChannel("127.0.0.1:10002"); - assertEquals("Can't find the corresponding channel, please check", str); - str = commands.disConnectMinerChannel("all"); - assertEquals("disconnect all channels...", str); - } - @Test public void testBalanceMaxXfer() { String str = commands.balanceMaxXfer(); diff --git a/src/test/java/io/xdag/consensus/SyncTest.java b/src/test/java/io/xdag/consensus/SyncTest.java index b4e93d2f8..2bc170bb4 100644 --- a/src/test/java/io/xdag/consensus/SyncTest.java +++ b/src/test/java/io/xdag/consensus/SyncTest.java @@ -325,7 +325,7 @@ public Kernel createKernel(TemporaryFolder root, boolean isNewVersion, int forkH KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); wallet.setAccounts(Collections.singletonList(key)); - Kernel kernel = new Kernel(config); + Kernel kernel = new Kernel(config, key); DatabaseFactory dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/java/io/xdag/core/BlockchainTest.java b/src/test/java/io/xdag/core/BlockchainTest.java index 3d1188590..df71c14b1 100644 --- a/src/test/java/io/xdag/core/BlockchainTest.java +++ b/src/test/java/io/xdag/core/BlockchainTest.java @@ -101,7 +101,7 @@ public void setUp() throws Exception { wallet.setAccounts(Collections.singletonList(key)); wallet.flush(); - kernel = new Kernel(config); + kernel = new Kernel(config, key); dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/java/io/xdag/core/ExtraBlockTest.java b/src/test/java/io/xdag/core/ExtraBlockTest.java index ac5067098..bfe836c1f 100644 --- a/src/test/java/io/xdag/core/ExtraBlockTest.java +++ b/src/test/java/io/xdag/core/ExtraBlockTest.java @@ -86,7 +86,7 @@ public void setUp() throws Exception { wallet.setAccounts(Collections.singletonList(key)); wallet.flush(); - kernel = new Kernel(config); + kernel = new Kernel(config, key); dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( @@ -236,7 +236,7 @@ public void startCheckMain(long period) { public void checkOrphan() { long nblk = this.getXdagStats().nnoref / 11; while (nblk-- > 0) { - Block linkBlock = createNewBlock(null, null, false, kernel.getConfig().getPoolSpec().getPoolTag()); + Block linkBlock = createNewBlock(null, null, false, kernel.getConfig().getNodeSpec().getNodeTag()); linkBlock.signOut(kernel.getWallet().getDefKey()); ImportResult result = this.tryToConnect(linkBlock); assertTrue(result == IMPORTED_BEST || result == IMPORTED_NOT_BEST); diff --git a/src/test/java/io/xdag/core/RandomXSyncTest.java b/src/test/java/io/xdag/core/RandomXSyncTest.java index 003db690d..c42bca425 100644 --- a/src/test/java/io/xdag/core/RandomXSyncTest.java +++ b/src/test/java/io/xdag/core/RandomXSyncTest.java @@ -35,7 +35,7 @@ import io.xdag.db.BlockStore; import io.xdag.db.OrphanBlockStore; import io.xdag.db.rocksdb.*; -import io.xdag.mine.randomx.RandomX; +import io.xdag.crypto.RandomX; import io.xdag.utils.XdagTime; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.time.FastDateFormat; @@ -192,7 +192,7 @@ public Kernel createKernel(TemporaryFolder root) throws Exception { KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); wallet.setAccounts(Collections.singletonList(key)); - Kernel kernel = new Kernel(config); + Kernel kernel = new Kernel(config, key); DatabaseFactory dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/java/io/xdag/core/RewardTest.java b/src/test/java/io/xdag/core/RewardTest.java index b23fa203e..2f23a4327 100644 --- a/src/test/java/io/xdag/core/RewardTest.java +++ b/src/test/java/io/xdag/core/RewardTest.java @@ -35,7 +35,7 @@ import io.xdag.db.BlockStore; import io.xdag.db.OrphanBlockStore; import io.xdag.db.rocksdb.*; -import io.xdag.mine.randomx.RandomX; +import io.xdag.crypto.RandomX; import io.xdag.utils.XdagTime; import org.apache.tuweni.bytes.Bytes32; import org.hyperledger.besu.crypto.KeyPair; @@ -84,7 +84,7 @@ public void setUp() throws Exception { wallet.setAccounts(Collections.singletonList(key)); wallet.flush(); - kernel = new Kernel(config); + kernel = new Kernel(config, key); dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/java/io/xdag/crypto/DnetKeysTest.java b/src/test/java/io/xdag/crypto/DnetKeysTest.java deleted file mode 100644 index 683a4cb3e..000000000 --- a/src/test/java/io/xdag/crypto/DnetKeysTest.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.crypto; - -import static org.junit.Assert.assertEquals; - -import io.xdag.config.Config; -import io.xdag.config.DevnetConfig; -import java.io.File; -import java.io.FileInputStream; -import java.util.Objects; -import org.apache.commons.io.IOUtils; -import org.junit.Before; -import org.junit.Test; - -public class DnetKeysTest { - - public final String cWord = "cdeee61f60df6185f5b90a95b00f4fe70dd2675df2150d777778780025f6947a3581f329cfd393ab042080e5e7f1bd75cd5877477550bebee9e7d09b92766b9c9a266793a646ee9fe0a6f1b66f36b88bd386ff302abe8492b8b63d2806db22bcc2cf420e7a5087374827fdb9cddae4d6581b11d60640a029dce9ff5050b46a9a991f6621ef9c3c1ff7c57800175f95f9c703f0c00ac123c88400bdc0c7d9060630b2919e49e3531e993fbb87b644a8013ded2ee60020c457b97270169e0de67a0279ad8de6230d5b455d95fd4997b3c2e65d681a8a7cc4c11d25bb159894556556c876f633619d21347a1c6458753033c5432670a6810e79b46bb549f48f733d7864e4c2cd7eac5a180b6823028658f4cce95c009578e86f4cb04bbf915a695138487784cc36922e676fa9ccad9dcaf2275e4a7255965fad83c49c4d6401119b70015e9baee5b68eed0cfb99a7214d150feac1c7ad81d7dca5d314c4fffeef9a090afed569f87a1d32512aa35d0ef6133f0e9eb1d3746bf5c16931bdf85fe85292eb934bff3dd6a506bae61d54bfac90e2b07bab4ad1dba15e2478a6ccfd5fd6e096c4be6ec47a117a99d9e051621d83f2def5ae90a6a437867a6225fd53570a4d3f0511730f2e2c3306c6d0b055bad55804f61f3ff2d4a38f00d31251187534903c2227183c787e3f42bc592b36f84ebe7a406b03d497765c15b9d2646244b8"; - public final String cPwd = "08d599aafccb4e64a97d31cc2e8204ac"; - public byte[] dnetKeys; - public Config config; - - @Before - public void setUp() throws Exception { - config = new DevnetConfig(); - config.initKeys(); - String absolutePath = Objects.requireNonNull(DnetKeysTest.class.getClassLoader().getResource("dnet_keys.bin")).getPath(); - File keyFile = new File(absolutePath); - - dnetKeys = new byte[3072]; - - IOUtils.read(new FileInputStream(keyFile), dnetKeys); - - byte[] prvKey = new byte[1024]; - byte[] pubKey = new byte[1024]; - byte[] encodedWord = new byte[512]; - byte[] word = new byte[512]; - - System.arraycopy(dnetKeys, 0, prvKey, 0, 1024); - System.arraycopy(dnetKeys, 1024, pubKey, 0, 1024); - System.arraycopy(dnetKeys, 2048, encodedWord, 0, 512); - System.arraycopy(dnetKeys, 2560, word, 0, 512); - } - - @Test - public void testInitKeys() { - - for (int i = 0; i < 3072; i++) { - if (i < 1024) { - assertEquals(dnetKeys[i], config.getNodeSpec().getXKeys().prv[i]); - } else if (i < 2048) { - assertEquals(dnetKeys[i], config.getNodeSpec().getXKeys().pub[i - 1024]); - } else if (i < 2560) { - assertEquals(dnetKeys[i], config.getNodeSpec().getXKeys().sect0_encoded[i - 2048]); - } else { - assertEquals(dnetKeys[i], config.getNodeSpec().getXKeys().sect0[i - 2560]); - } - } - } -} diff --git a/src/test/java/io/xdag/crypto/Libp2pCryptoTest.java b/src/test/java/io/xdag/crypto/Libp2pCryptoTest.java deleted file mode 100644 index f9f49ab34..000000000 --- a/src/test/java/io/xdag/crypto/Libp2pCryptoTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.crypto; - -import static org.junit.Assert.assertArrayEquals; - -import io.libp2p.core.crypto.PrivKey; -import io.libp2p.core.crypto.PubKey; -import io.libp2p.crypto.keys.Secp256k1Kt; -import io.xdag.utils.Numeric; -import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; - -public class Libp2pCryptoTest { - - private PrivKey libp2pPrivKey; - private PubKey libp2pPubKey; - - @Before - public void setUp() { - libp2pPrivKey = Secp256k1Kt - .unmarshalSecp256k1PrivateKey(Numeric.hexStringToByteArray(SampleKeys.PRIVATE_KEY_STRING)); - libp2pPubKey = Secp256k1Kt - .unmarshalSecp256k1PublicKey(Numeric.hexStringToByteArray(SampleKeys.PUBLIC_KEY_COMPRESS_STRING)); - } - - @Test - public void testUnmarshalSecp256k1PrivateKey() { - Bytes libp2pBytes = Bytes.wrap(libp2pPrivKey.raw()).slice(1, 33 -1); - assertArrayEquals(libp2pBytes.toArray(), SampleKeys.KEY_PAIR.getPrivateKey().getEncoded()); - } - - @Test - public void testUnmarshalSecp256k1PublicKey() { - assertArrayEquals(libp2pPubKey.raw(), SampleKeys.KEY_PAIR.getPublicKey().asEcPoint(Sign.CURVE).getEncoded(true)); - } -} \ No newline at end of file diff --git a/src/test/java/io/xdag/db/SnapshotStoreTest.java b/src/test/java/io/xdag/db/SnapshotStoreTest.java index 85974519e..44c057d73 100644 --- a/src/test/java/io/xdag/db/SnapshotStoreTest.java +++ b/src/test/java/io/xdag/db/SnapshotStoreTest.java @@ -34,7 +34,7 @@ import io.xdag.crypto.SampleKeys; import io.xdag.crypto.Sign; import io.xdag.db.rocksdb.*; -import io.xdag.mine.randomx.RandomX; +import io.xdag.crypto.RandomX; import io.xdag.utils.BasicUtils; import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; @@ -122,7 +122,7 @@ public void setUp() throws Exception { wallet.setAccounts(Collections.singletonList(key)); wallet.flush(); - kernel = new Kernel(config); + kernel = new Kernel(config, key); dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/java/io/xdag/mine/miner/MinerConnectTest.java b/src/test/java/io/xdag/mine/miner/MinerConnectTest.java deleted file mode 100644 index 243ef245d..000000000 --- a/src/test/java/io/xdag/mine/miner/MinerConnectTest.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.mine.miner; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.embedded.EmbeddedChannel; -import io.xdag.Kernel; -import io.xdag.Wallet; -import io.xdag.config.Config; -import io.xdag.config.DevnetConfig; -import io.xdag.core.BlockchainImpl; -import io.xdag.crypto.Keys; -import io.xdag.crypto.SampleKeys; -import io.xdag.crypto.Sign; -import io.xdag.db.AddressStore; -import io.xdag.db.BlockStore; -import io.xdag.db.OrphanBlockStore; -import io.xdag.db.rocksdb.*; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.handler.MinerHandShakeHandler; -import io.xdag.utils.BytesUtils; -import org.apache.tuweni.bytes.Bytes32; -import org.hyperledger.besu.crypto.KeyPair; -import org.hyperledger.besu.crypto.SECPPrivateKey; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Collections; -import java.util.List; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class MinerConnectTest { - - @Rule - public TemporaryFolder root = new TemporaryFolder(); - - Config config = new DevnetConfig(); - Wallet wallet; - String pwd; - Kernel kernel; - DatabaseFactory dbFactory; - AddressStore addressStore; - MinerChannel channel; - BlockchainImpl blockchain; - BigInteger private_1 = new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16); - SECPPrivateKey secretkey_1 = SECPPrivateKey.create(private_1, Sign.CURVE_NAME); - @Before - public void setUp() throws Exception { - KeyPair addrKey = KeyPair.create(secretkey_1, Sign.CURVE, Sign.CURVE_NAME); - config.getNodeSpec().setStoreDir(root.newFolder().getAbsolutePath()); - config.getNodeSpec().setStoreBackupDir(root.newFolder().getAbsolutePath()); - - pwd = "password"; - wallet = new Wallet(config); - wallet.unlock(pwd); - KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); - wallet.setAccounts(Collections.singletonList(key)); - wallet.flush(); - - kernel = new Kernel(config); - dbFactory = new RocksdbFactory(config); - - BlockStore blockStore = new BlockStoreImpl( - dbFactory.getDB(DatabaseName.INDEX), - dbFactory.getDB(DatabaseName.TIME), - dbFactory.getDB(DatabaseName.BLOCK), - dbFactory.getDB(DatabaseName.TXHISTORY)); - - blockStore.reset(); - - AddressStore addressStore = new AddressStoreImpl(dbFactory.getDB(DatabaseName.ADDRESS)); - - addressStore.reset(); - - OrphanBlockStore orphanBlockStore = new OrphanBlockStoreImpl(dbFactory.getDB(DatabaseName.ORPHANIND)); - orphanBlockStore.reset(); - - kernel.setBlockStore(blockStore); - kernel.setOrphanBlockStore(orphanBlockStore); - kernel.setWallet(wallet); - - blockchain = new BlockchainImpl(kernel); - - channel = new MinerChannel(kernel, false); - } - - @After - public void tearDown() throws IOException { - wallet.delete(); - } - - @Test - public void testMinerConnect() - throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { -// Native.crypt_start(); - KeyPair key = Keys.createEcKeyPair(); - byte[] address = Keys.toBytesAddress(key); - ByteBuf buf = Unpooled.buffer(); - buf.writeBytes(address); - ByteBuf buf1 = buf.duplicate(); - //2、创建EmbeddedChannel,并添加一个MinerHandshakeHandler - EmbeddedChannel embeddedChannel = new EmbeddedChannel(new MockMinerHandshakeHandler(channel, kernel)); - - //3、将数据写入 EmbeddedChannel - boolean writeInbound = embeddedChannel.writeInbound(buf1.retain()); - assertTrue(writeInbound); - //4、标记 Channel 为已完成状态 - boolean finish = embeddedChannel.finish(); - assertTrue(finish); - - //5、读取数据 - ByteBuf readInbound = embeddedChannel.readInbound(); - assertEquals(1, readInbound.readInt()); - } -} - class MockMinerHandshakeHandler extends MinerHandShakeHandler { - - public MockMinerHandshakeHandler(MinerChannel channel, Kernel kernel) { - super(channel, kernel); - } - - @Override - public boolean initMiner(Bytes32 hash) { - return true; - } - - @Override - protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { - if (in.readableBytes() >= 20) { - ByteBuf byteBuf = Unpooled.buffer(); - byte[] address = new byte[20]; - in.readBytes(address); - - System.arraycopy(BytesUtils.longToBytes(0, true), 0, address, 0, 8); - - if (!initMiner(BytesUtils.arrayToByte32(address))) { - ctx.close(); - } - byteBuf.writeInt(1); - out.add(byteBuf.retain()); - } - } -} diff --git a/src/test/java/io/xdag/consensus/XdagPowTest.java b/src/test/java/io/xdag/net/CapabilityTest.java similarity index 63% rename from src/test/java/io/xdag/consensus/XdagPowTest.java rename to src/test/java/io/xdag/net/CapabilityTest.java index 97fa57cb0..546c59807 100644 --- a/src/test/java/io/xdag/consensus/XdagPowTest.java +++ b/src/test/java/io/xdag/net/CapabilityTest.java @@ -21,34 +21,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.consensus; +package io.xdag.net; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -import io.xdag.mine.MinerChannel; -import io.xdag.mine.message.TaskShareMessage; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -@RunWith(MockitoJUnitRunner.class) -public class XdagPowTest { - - @Mock - XdagPow xdagPow; +public class CapabilityTest { @Test - public void testReceiveNewShareOnTimer(){ - //mock 1000 miners send share - MinerChannel channel = mock(MinerChannel.class); - TaskShareMessage msg = mock(TaskShareMessage.class); - - xdagPow.receiveNewShare(channel, msg); - - verify(xdagPow).receiveNewShare(channel, msg); + public void testIsSupported() { + assertFalse(CapabilityTreeSet.emptyList().isSupported(Capability.FULL_NODE)); + assertFalse(CapabilityTreeSet.of("FULL_NODE").isSupported(Capability.LIGHT_NODE)); + assertTrue(CapabilityTreeSet.of("FULL_NODE").isSupported(Capability.FULL_NODE)); + assertTrue(CapabilityTreeSet.of(Capability.FULL_NODE).isSupported(Capability.FULL_NODE)); + assertEquals(CapabilityTreeSet.of(Capability.FULL_NODE), CapabilityTreeSet.of(Capability.FULL_NODE)); } - - } diff --git a/src/test/java/io/xdag/net/XdagChannelManagerTest.java b/src/test/java/io/xdag/net/ChannelManagerTest.java similarity index 86% rename from src/test/java/io/xdag/net/XdagChannelManagerTest.java rename to src/test/java/io/xdag/net/ChannelManagerTest.java index 445e277eb..6ec7385d5 100644 --- a/src/test/java/io/xdag/net/XdagChannelManagerTest.java +++ b/src/test/java/io/xdag/net/ChannelManagerTest.java @@ -29,15 +29,19 @@ import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; -import io.xdag.net.manager.XdagChannelManager; +import io.xdag.crypto.SampleKeys; +import io.xdag.crypto.Sign; + import java.net.InetSocketAddress; import java.util.List; + +import org.hyperledger.besu.crypto.KeyPair; import org.junit.Before; import org.junit.Test; import com.google.common.collect.Lists; -public class XdagChannelManagerTest { +public class ChannelManagerTest { Config config = new DevnetConfig(); Kernel kernel; @@ -50,12 +54,13 @@ public void setUp() throws Exception { addressList.add(new InetSocketAddress(address.split(":")[0],Integer.parseInt(address.split(":")[1]))); } config.getNodeSpec().setWhiteIPList(addressList); - kernel = new Kernel(config); + KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); + kernel = new Kernel(config, key); } @Test public void testIp() { - XdagChannelManager channelManager = new XdagChannelManager(kernel); + ChannelManager channelManager = new ChannelManager(kernel); InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 1001); assertTrue(channelManager.isAcceptable(inetSocketAddress)); } diff --git a/src/test/java/io/xdag/mine/handler/ConnectionLimitHandlerTest.java b/src/test/java/io/xdag/net/ConnectionLimitHandlerTest.java similarity index 99% rename from src/test/java/io/xdag/mine/handler/ConnectionLimitHandlerTest.java rename to src/test/java/io/xdag/net/ConnectionLimitHandlerTest.java index aa3b1ffb7..556beb902 100644 --- a/src/test/java/io/xdag/mine/handler/ConnectionLimitHandlerTest.java +++ b/src/test/java/io/xdag/net/ConnectionLimitHandlerTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.mine.handler; +package io.xdag.net; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/src/test/java/io/xdag/net/FrameTest.java b/src/test/java/io/xdag/net/FrameTest.java new file mode 100644 index 000000000..fc29aeb74 --- /dev/null +++ b/src/test/java/io/xdag/net/FrameTest.java @@ -0,0 +1,55 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +public class FrameTest { + + @Test + public void testReadAndWrite() { + short version = 0x1122; + byte compressType = 0x33; + byte packetType = 0x44; + int packetId = 0x55667788; + int packetSize = 0x99aabbcc; + int bodySize = 0xddeeff00; + Frame frame = new Frame(version, compressType, packetType, packetId, packetSize, bodySize, null); + + ByteBuf buf = Unpooled.copiedBuffer(new byte[Frame.HEADER_SIZE]); + + buf.writerIndex(0); + frame.writeHeader(buf); + + buf.readerIndex(0); + Frame frame2 = Frame.readHeader(buf); + + assertThat(frame2).isEqualToComparingFieldByFieldRecursively(frame); + } +} diff --git a/src/test/java/io/xdag/net/MessageTest.java b/src/test/java/io/xdag/net/MessageTest.java index eabf1f338..7df36da42 100644 --- a/src/test/java/io/xdag/net/MessageTest.java +++ b/src/test/java/io/xdag/net/MessageTest.java @@ -26,9 +26,9 @@ import static org.junit.Assert.assertEquals; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.net.message.impl.SumReplyMessage; +import io.xdag.net.message.MessageCode; +import io.xdag.net.message.consensus.SumReplyMessage; +import io.xdag.net.message.consensus.XdagMessage; import io.xdag.utils.BytesUtils; import java.net.InetAddress; import java.net.UnknownHostException; @@ -254,18 +254,18 @@ public class MessageTest { * } **/ - public void printMessage(AbstractMessage message) { - System.out.println(message.getCommand()); + public void printMessage(XdagMessage message) { + System.out.println(message.getCode().name()); System.out.println("starttime:" + message.getStarttime()); System.out.println("endtime:" + message.getEndtime()); System.out.println("status:" + message.getXdagStats()); - System.out.println("netdb:" + message.getNetDB()); - if (message.getCommand() == XdagMessageCodes.BLOCK_REQUEST) { + System.out.println("netdb:" + message.getRemoteNetdb()); + if (message.getCode() == MessageCode.BLOCK_REQUEST) { System.out.println("request hash:" + message.getHash().toHexString()); } else { System.out.println("random:" + message.getRandom()); } - if (message.getCommand() == XdagMessageCodes.SUMS_REPLY) { + if (message.getCode() == MessageCode.SUMS_REPLY) { SumReplyMessage sumReplyMessage = (SumReplyMessage) message; System.out.println("sum:" + sumReplyMessage.getSum().toHexString()); } diff --git a/src/test/java/io/xdag/net/NetTest.java b/src/test/java/io/xdag/net/NetTest.java index e5c6dfebc..bebe3a55c 100644 --- a/src/test/java/io/xdag/net/NetTest.java +++ b/src/test/java/io/xdag/net/NetTest.java @@ -26,8 +26,10 @@ import static org.junit.Assert.assertEquals; -import io.xdag.net.message.NetDB; -import io.xdag.net.message.impl.SumRequestMessage; +import java.math.BigInteger; + +import io.xdag.core.XdagStats; +import io.xdag.net.message.consensus.SumRequestMessage; import io.xdag.utils.BytesUtils; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.MutableBytes; @@ -64,8 +66,8 @@ public void testNetDB() { assertEquals(all, Hex.toHexString(netDB1.getEncoded())); MutableBytes mutableBytes = MutableBytes.create(112); - long nhosts = netDB.getIpList().size(); - long totalHosts = netDB.getIpList().size(); + long nhosts = netDB.getIPList().size(); + long totalHosts = netDB.getIPList().size(); mutableBytes.set(0, Bytes.wrap(BytesUtils.longToBytes(nhosts, true))); mutableBytes.set(8, Bytes.wrap(BytesUtils.longToBytes(totalHosts, true))); @@ -86,27 +88,37 @@ public void testNetUpdate() { @Test public void testNetDBParse() { - String sumsRequest = "8b010002f91eb6eb200000000000000000000000000000000000000000000100" - + "257b369b5a89d009000000000000000000000000000000000000000000000000" - + "511e9e9274800c750200000000000000511e9e9274800c750200000000000000" - + "ee00000000000000ee00000000000000d400000000000000d400000000000000" - + "04000000040000003ef47801000000007f000001611e7f000001b8227f000001" - + "5f767f000001d49d000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000" - + "0000000000000000000000000000000000000000000000000000000000000000"; - - // SumRequestMessage sumRequestMessage = new SumRequestMessage(Hex.decode(sumsRequest)); - SumRequestMessage sumRequestMessage = new SumRequestMessage(Bytes.fromHexString(sumsRequest).mutableCopy()); - NetDB netDB = sumRequestMessage.getNetDB(); - assertEquals(4, netDB.getSize()); + long starttime = 1600616700000L; + long endtime = starttime + 10000; + + XdagStats stats = new XdagStats(); + stats.maxdifficulty = BigInteger.TWO; + stats.totalnblocks = 10001; + stats.totalnmain = 1001; + stats.totalnhosts = 11; + stats.maintime = endtime; + + NetDB netDB = new NetDB(); + netDB.addNewIP("10.0.0.1", 8001); + netDB.addNewIP("10.0.0.2", 8001); + netDB.addNewIP("10.0.0.3", 8001); + netDB.addNewIP("10.0.0.4", 8001); + + SumRequestMessage sumRequestMessage = new SumRequestMessage(starttime, endtime, stats, netDB); + + String hexString = Bytes.wrap(sumRequestMessage.getBody()).toHexString(); + + sumRequestMessage = new SumRequestMessage(Bytes.fromHexString(hexString).toArray()); + + assertEquals(starttime, sumRequestMessage.getStarttime()); + assertEquals(endtime, sumRequestMessage.getEndtime()); + + XdagStats xdagStats = sumRequestMessage.getXdagStats(); + assertEquals(BigInteger.TWO, xdagStats.maxdifficulty); + assertEquals(stats.totalnblocks, xdagStats.totalnblocks); + assertEquals(stats.totalnmain, xdagStats.totalnmain); + assertEquals(stats.totalnhosts, xdagStats.totalnhosts); + assertEquals(stats.maintime, xdagStats.maintime); } } diff --git a/src/test/java/io/xdag/net/NodeManagerTest.java b/src/test/java/io/xdag/net/NodeManagerTest.java index 35f958e99..58ac85ed0 100644 --- a/src/test/java/io/xdag/net/NodeManagerTest.java +++ b/src/test/java/io/xdag/net/NodeManagerTest.java @@ -28,9 +28,13 @@ import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; -import io.xdag.net.manager.NetDBManager; +import io.xdag.crypto.SampleKeys; +import io.xdag.crypto.Sign; + import java.net.InetSocketAddress; import java.util.List; + +import org.hyperledger.besu.crypto.KeyPair; import org.junit.Before; import org.junit.Test; @@ -49,8 +53,9 @@ public void setUp() throws Exception { InetSocketAddress inetSocketAddress = new InetSocketAddress(address.split(":")[0],Integer.parseInt(address.split(":")[1])); addressList.add(inetSocketAddress); } + KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); config.getNodeSpec().setWhiteIPList(addressList); - kernel = new Kernel(config); + kernel = new Kernel(config, key); } @Test diff --git a/src/test/java/io/xdag/net/WhliteListTest.java b/src/test/java/io/xdag/net/WhliteListTest.java index d7ccbaadd..bfdf088b7 100644 --- a/src/test/java/io/xdag/net/WhliteListTest.java +++ b/src/test/java/io/xdag/net/WhliteListTest.java @@ -30,8 +30,14 @@ import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; +import io.xdag.crypto.Keys; + import java.net.InetSocketAddress; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.util.List; + import org.junit.Before; import org.junit.Test; @@ -43,7 +49,7 @@ public class WhliteListTest { Config config = new DevnetConfig(); @Before - public void setup() { + public void setup() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { // 初始化白名单 String[] list = new String[]{"124.34.34.1:1001", "127.0.0.1:1002"}; List addressList = Lists.newArrayList(); @@ -51,12 +57,13 @@ public void setup() { addressList.add(new InetSocketAddress(address.split(":")[0],Integer.parseInt(address.split(":")[1]))); } config.getNodeSpec().setWhiteIPList(addressList); - kernel = new Kernel(config); + kernel = new Kernel(config, Keys.createEcKeyPair()); } @Test - public void WhileList() { - XdagClient client = new XdagClient(config); + public void WhileList() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException { + PeerClient client = new PeerClient(config, Keys.createEcKeyPair()); // 新增白名单节点 client.addWhilteIP("127.0.0.1", 8882); //白名单有的节点 diff --git a/src/test/java/io/xdag/net/libp2p/DiscoveryPeerTest.java b/src/test/java/io/xdag/net/libp2p/DiscoveryPeerTest.java deleted file mode 100644 index a7f83d84c..000000000 --- a/src/test/java/io/xdag/net/libp2p/DiscoveryPeerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import static org.junit.Assert.assertEquals; - -import io.libp2p.core.PeerId; -import io.libp2p.core.crypto.KEY_TYPE; -import io.libp2p.core.crypto.KeyKt; -import io.libp2p.core.crypto.PrivKey; -import io.xdag.net.libp2p.discovery.DiscoveryPeer; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; - -public class DiscoveryPeerTest { - - DiscoveryPeer peer; - String expectStirng; - - @Before - public void start() throws UnknownHostException { - PrivKey privKey = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).component1(); - peer = new DiscoveryPeer( - Bytes.wrap(privKey.publicKey().raw()), - new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 10000)); - expectStirng = - "/ip4/127.0.0.1/tcp/10000/ipfs/" + new LibP2PNodeId(PeerId.fromPubKey(privKey.publicKey())).toString(); - - } - - @Test - public void TestDiscoveryPeerToDailNodeId() { - assertEquals(expectStirng, Libp2pUtils.discoveryPeerToDailId(peer)); - } -} diff --git a/src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java b/src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java deleted file mode 100644 index d5f84c4ee..000000000 --- a/src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import io.libp2p.core.PeerId; -import io.libp2p.core.crypto.KEY_TYPE; -import io.libp2p.core.crypto.KeyKt; -import io.libp2p.core.crypto.PrivKey; -import io.libp2p.core.multiformats.Multiaddr; -import io.xdag.net.libp2p.peer.NodeId; -import java.net.InetSocketAddress; -import org.junit.Before; -import org.junit.Test; - -public class Libp2pNetworkTest { - - //node 0 - PrivKey privKey0 = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1, 0).getFirst(); - PeerId peerId0 = PeerId.fromPubKey(privKey0.publicKey()); - NodeId nodeId0 = new LibP2PNodeId(peerId0); - Multiaddr advertisedAddr = - Libp2pUtils.fromInetSocketAddress( - new InetSocketAddress("127.0.0.1", 11111), nodeId0); - Libp2pNetwork node0 = new Libp2pNetwork(privKey0, advertisedAddr); - - // node 1 - PrivKey privKey1 = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1, 0).getFirst(); - PeerId peerId1 = PeerId.fromPubKey(privKey1.publicKey()); - NodeId nodeId1 = new LibP2PNodeId(peerId1); - Multiaddr advertisedAddr1 = - Libp2pUtils.fromInetSocketAddress( - new InetSocketAddress("127.0.0.1", 12121), nodeId1); - Libp2pNetwork node1 = new Libp2pNetwork(privKey1, advertisedAddr1); - - @Before - public void startup() { - node0.start(); - node1.start(); - } - - @Test - public void testlibp2pconnect() throws InterruptedException { - // Alternative connection format - String peer0 = advertisedAddr.toString(); - peer0 = peer0.replaceAll("p2p", "ipfs"); - // connect - node1.dail(peer0); - // wait connect success - Thread.sleep(1000); -// assert node1.peerManager.getPeerCount() == 1; - NonProtocol rpc = (NonProtocol) node1.getProtocol(); - assert rpc.getConnection().remoteAddress().toString().equals(advertisedAddr.toString().substring(0, 24)); - } -} \ No newline at end of file diff --git a/src/test/java/io/xdag/net/libp2p/Libp2pUtilsTest.java b/src/test/java/io/xdag/net/libp2p/Libp2pUtilsTest.java deleted file mode 100644 index 0e6cdc919..000000000 --- a/src/test/java/io/xdag/net/libp2p/Libp2pUtilsTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p; - -import static io.xdag.net.libp2p.Libp2pUtils.convertToDiscoveryPeer; -import static org.assertj.core.api.Assertions.assertThat; - -import io.xdag.net.libp2p.discovery.DiscoveryPeer; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Optional; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.units.bigints.UInt64; -import org.ethereum.beacon.discovery.schema.EnrField; -import org.ethereum.beacon.discovery.schema.IdentitySchema; -import org.ethereum.beacon.discovery.schema.NodeRecord; -import org.ethereum.beacon.discovery.schema.NodeRecordFactory; -import org.junit.Test; - -public class Libp2pUtilsTest { - - private static final Bytes PUB_KEY = - Bytes.fromHexString("0x0295A5A50F083697FF8557F3C6FE0CDF8E8EC2141D15F19A5A45571ED9C38CE181"); - private static final Bytes IPV6_LOCALHOST = - Bytes.fromHexString("0x00000000000000000000000000000001"); - - @Test - public void shouldConvertRealEnrToDiscoveryPeer() throws Exception { - final String enr = - "-Iu4QMmfe-EkDnVX6k5i2LFTiDQ-q4-Cb1I01iRI-wbCD_r4Z8eujNCgZDmZXb1ZOPi1LfJaNx3Bd0QUK9wqBjwUXJQBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQO4btn3R6f6mZY_OeOxdrRenoYxCKLRReo6TnbY0JNRlIN0Y3CCIyiDdWRwgiMo"; - - final NodeRecord nodeRecord = NodeRecordFactory.DEFAULT.fromBase64(enr); - - final DiscoveryPeer expectedPeer = - new DiscoveryPeer( - Bytes.fromHexString( - "0x03B86ED9F747A7FA99963F39E3B176B45E9E863108A2D145EA3A4E76D8D0935194"), - new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 9000)); - assertThat(convertToDiscoveryPeer(nodeRecord)).contains(expectedPeer); - } - - @Test - public void shouldNotConvertRecordWithNoIp() { - assertThat(convertNodeRecordWithFields()).isEmpty(); - } - - @Test - public void shouldNotConvertRecordWithIpButNoPort() { - assertThat( - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V4, Bytes.wrap(new byte[]{127, 0, 0, 1})))) - .isEmpty(); - } - - @Test - public void shouldNotConvertRecordWithIpAndUdpPortButNoTcpPort() { - assertThat( - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V4, Bytes.wrap(new byte[]{127, 0, 0, 1})), - new EnrField(EnrField.UDP, 30303))) - .isEmpty(); - } - - @Test - public void shouldUseV4PortIfV6PortSpecifiedWithNoV6Ip() { - assertThat( - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V6, IPV6_LOCALHOST), new EnrField(EnrField.TCP, 30303))) - .contains(new DiscoveryPeer(PUB_KEY, new InetSocketAddress("::1", 30303))); - } - - @Test - public void shouldNotConvertRecordWithV4IpAndV6Port() { - assertThat( - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V4, IPV6_LOCALHOST), new EnrField(EnrField.TCP_V6, 30303))) - .isEmpty(); - } - - @Test - public void shouldNotConvertRecordWithPortButNoIp() { - assertThat(convertNodeRecordWithFields(new EnrField(EnrField.TCP, 30303))).isEmpty(); - } - - @Test - public void shouldConvertIpV4Record() { - // IP address bytes are unsigned. Make sure we handle that correctly. - final Optional result = - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V4, Bytes.wrap(new byte[]{-127, 24, 31, 22})), - new EnrField(EnrField.TCP, 1234)); - assertThat(result) - .contains(new DiscoveryPeer(PUB_KEY, new InetSocketAddress("129.24.31.22", 1234))); - } - - @Test - public void shouldConvertIpV6Record() { - final Optional result = - convertNodeRecordWithFields( - new EnrField(EnrField.IP_V6, IPV6_LOCALHOST), new EnrField(EnrField.TCP_V6, 1234)); - assertThat(result).contains(new DiscoveryPeer(PUB_KEY, new InetSocketAddress("::1", 1234))); - } - - private Optional convertNodeRecordWithFields(final EnrField... fields) { - return convertToDiscoveryPeer(createNodeRecord(fields)); - } - - private NodeRecord createNodeRecord(final EnrField... fields) { - final ArrayList fieldList = new ArrayList<>(Arrays.asList(fields)); - fieldList.add(new EnrField(EnrField.ID, IdentitySchema.V4)); - fieldList.add(new EnrField(EnrField.PKEY_SECP256K1, PUB_KEY)); - return NodeRecordFactory.DEFAULT.createFromValues(UInt64.ZERO, fieldList); - } - -} \ No newline at end of file diff --git a/src/test/java/io/xdag/net/libp2p/discovery/DiscoveryPeerTest.java b/src/test/java/io/xdag/net/libp2p/discovery/DiscoveryPeerTest.java deleted file mode 100644 index 2aa99fb11..000000000 --- a/src/test/java/io/xdag/net/libp2p/discovery/DiscoveryPeerTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2020-2030 The XdagJ Developers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package io.xdag.net.libp2p.discovery; - -import io.libp2p.core.crypto.KEY_TYPE; -import io.libp2p.core.crypto.KeyKt; -import io.libp2p.core.crypto.PrivKey; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.util.Collections; -import java.util.List; -import org.apache.tuweni.bytes.Bytes; -import org.junit.Before; -import org.junit.Test; - -import com.google.common.collect.Lists; - -public class DiscoveryPeerTest { - - DiscV5Service discV5Service1; - DiscV5Service discV5Service2; - DiscoveryPeer discoveryPeer; - - @Before - public void startup() throws UnknownHostException { - - String priString = "0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5"; - Bytes privkeybytes = Bytes.fromHexString(priString); - PrivKey privKey = KeyKt.unmarshalPrivateKey(privkeybytes.toArrayUnsafe()); -// PrivKey privKey1 = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).component1(); -// String s = Hex.toHexString(privKey1.bytes()); -// System.out.println(Arrays.toString(Hex.decode(s))); - discoveryPeer = new DiscoveryPeer( - Bytes.wrap(privKey.publicKey().raw()), - new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 10001)); -// System.out.println(discoveryPeer.getNodeAddress().toString()); - List boot = Lists.newArrayList(); - Bytes bytes = Bytes.wrap(privKey.raw()); - discV5Service1 = DiscV5Service.create((bytes), - "127.0.0.1", - 10001, - Collections.emptyList()); - if (discV5Service1.getEnr().isPresent()) { - boot.add(discV5Service1.getEnr().get()); - } - discV5Service2 = DiscV5Service.create(Bytes.wrap(KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).component1().raw()), - "127.0.0.1", 11111, boot); - discV5Service1.start(); - discV5Service1.searchForPeers(); - - discV5Service2.start(); - discV5Service2.searchForPeers(); - } - - @Test - public void ShouldFindTheSeedNode() throws InterruptedException { - Thread.sleep(1000); - assert discV5Service2.streamKnownPeers().findFirst().isEmpty() || discoveryPeer - .equals(discV5Service2.streamKnownPeers().findFirst().get()); - } - - @Test - public void exitnetwork() throws InterruptedException { - discV5Service2.stop(); - Thread.sleep(1000); - assert discV5Service1.streamKnownPeers().count() == 0; - } - -} \ No newline at end of file diff --git a/src/test/java/io/xdag/net/libp2p/MultiaddrTest.java b/src/test/java/io/xdag/net/message/MessageCodeTest.java similarity index 69% rename from src/test/java/io/xdag/net/libp2p/MultiaddrTest.java rename to src/test/java/io/xdag/net/message/MessageCodeTest.java index 6a2adbc1a..7818be4ff 100644 --- a/src/test/java/io/xdag/net/libp2p/MultiaddrTest.java +++ b/src/test/java/io/xdag/net/message/MessageCodeTest.java @@ -21,24 +21,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ - -package io.xdag.net.libp2p; +package io.xdag.net.message; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; -import io.libp2p.core.multiformats.Multiaddr; -import io.libp2p.core.multiformats.Protocol; import org.junit.Test; -public class MultiaddrTest { +public class MessageCodeTest { @Test - public void testGetIpAndPort() { - Multiaddr multiaddr = Multiaddr.fromString("/ip4/127.0.0.1/tcp/40002"); - String ip = Protocol.IP4.bytesToAddress(multiaddr.getFirstComponent(Protocol.IP4).getValue()); - String port = Protocol.TCP.bytesToAddress(multiaddr.getFirstComponent(Protocol.TCP).getValue()); - assertEquals("127.0.0.1", ip); - assertEquals("40002", port); + public void testConverting() { + for (MessageCode code : MessageCode.values()) { + assertEquals(code, MessageCode.of(code.getCode())); + assertEquals(code, MessageCode.of(code.toByte())); + } } + @Test + public void testNegativeByte() { + byte b = (byte) 0xff; + assertNull(MessageCode.of(b)); + } } diff --git a/src/main/java/io/xdag/net/handler/Xdag.java b/src/test/java/io/xdag/net/message/MessageFactoryTest.java similarity index 68% rename from src/main/java/io/xdag/net/handler/Xdag.java rename to src/test/java/io/xdag/net/message/MessageFactoryTest.java index 45b07cd7e..dd9e82e4c 100644 --- a/src/main/java/io/xdag/net/handler/Xdag.java +++ b/src/test/java/io/xdag/net/message/MessageFactoryTest.java @@ -21,29 +21,23 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message; -package io.xdag.net.handler; +import static org.junit.Assert.assertNull; -import io.xdag.core.Block; -import io.xdag.net.XdagVersion; -import io.xdag.net.message.Message; -import org.apache.tuweni.bytes.MutableBytes32; +import org.junit.Test; -public interface Xdag { +public class MessageFactoryTest { - XdagVersion getVersion(); + @Test + public void testNonExist() throws MessageException { + MessageFactory factory = new MessageFactory(); + assertNull(factory.create((byte) 0xff, new byte[1])); + } - void sendNewBlock(Block newBlock, int ttl); - - long sendGetBlocks(long startTime, long endTime); - - long sendGetBlock(MutableBytes32 hash, boolean isOld); - - long sendGetSums(long startTime, long endTime); - - void dropConnection(); - - void activate(); - - void sendMessage(Message message); + @Test(expected = MessageException.class) + public void testWrongCodec() throws MessageException { + MessageFactory factory = new MessageFactory(); + factory.create((byte) 0x01, new byte[1]); + } } diff --git a/src/test/java/io/xdag/mine/miner/MinerCalculateTest.java b/src/test/java/io/xdag/net/message/ReasonCodeTest.java similarity index 68% rename from src/test/java/io/xdag/mine/miner/MinerCalculateTest.java rename to src/test/java/io/xdag/net/message/ReasonCodeTest.java index c9baadf1d..fc99e520a 100644 --- a/src/test/java/io/xdag/mine/miner/MinerCalculateTest.java +++ b/src/test/java/io/xdag/net/message/ReasonCodeTest.java @@ -21,31 +21,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message; -package io.xdag.mine.miner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; -import org.junit.Assert; import org.junit.Test; -public class MinerCalculateTest { +public class ReasonCodeTest { @Test - public void movingAverageDouble() { -// double res = MinerCalculate.movingAverageDouble(100, 200, 300); -// System.out.println(res); + public void testConverting() { + for (ReasonCode code : ReasonCode.values()) { + assertEquals(code, ReasonCode.of(code.getCode())); + assertEquals(code, ReasonCode.of(code.toByte())); + } } @Test - public void minerCalculateUnpaidSharesTest() { - double sum = 265.56357765870297; - int count = 16; - - double res = MinerCalculate.diffToPay(0, 0); - Assert.assertTrue(Double.compare(0, res) >= 0); - - Double a = 0.000001; - Assert.assertTrue(a.compareTo((double) 0) > 0); - - + public void testNegativeByte() { + byte b = (byte) 0xff; + assertNull(MessageCode.of(b)); } } diff --git a/src/test/java/io/xdag/net/message/p2p/HelloMessageTest.java b/src/test/java/io/xdag/net/message/p2p/HelloMessageTest.java new file mode 100644 index 000000000..c23ad6742 --- /dev/null +++ b/src/test/java/io/xdag/net/message/p2p/HelloMessageTest.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import static io.xdag.utils.WalletUtils.toBase58; +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.hyperledger.besu.crypto.KeyPair; +import org.junit.Test; + +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; +import io.xdag.crypto.Keys; +import io.xdag.crypto.SampleKeys; +import io.xdag.crypto.SecureRandomUtils; +import io.xdag.crypto.Sign; +import io.xdag.net.CapabilityTreeSet; +import io.xdag.net.Peer; + +public class HelloMessageTest { + + @Test + public void testCodec() { + Config config = new DevnetConfig(); + + KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME);; + String peerId = toBase58(Keys.toBytesAddress(key)); + HelloMessage msg = new HelloMessage(config.getNodeSpec().getNetwork(), config.getNodeSpec().getNetworkVersion(), peerId, 8001, + config.getClientId(), config.getClientCapabilities().toArray(), 2, + SecureRandomUtils.secureRandom().generateSeed(InitMessage.SECRET_LENGTH), key); + assertTrue(msg.validate(config)); + + msg = new HelloMessage(msg.getBody()); + assertTrue(msg.validate(config)); + + String ip = "127.0.0.2"; + Peer peer = msg.getPeer(ip); + assertEquals(config.getNodeSpec().getNetwork(), peer.getNetwork()); + assertEquals(config.getNodeSpec().getNetworkVersion(), peer.getNetworkVersion()); + assertEquals(toBase58(Keys.toBytesAddress(key)), peer.getPeerId()); + assertEquals(ip, peer.getIp()); + assertEquals(config.getNodeSpec().getNodePort(), peer.getPort()); + assertEquals(config.getClientId(), peer.getClientId()); + assertEquals(config.getClientCapabilities(), CapabilityTreeSet.of(peer.getCapabilities())); + assertEquals(2, peer.getLatestBlockNumber()); + } +} diff --git a/src/test/java/io/xdag/net/libp2p/discovery/DiscoveryNetworkTest.java b/src/test/java/io/xdag/net/message/p2p/InitMessageTest.java similarity index 64% rename from src/test/java/io/xdag/net/libp2p/discovery/DiscoveryNetworkTest.java rename to src/test/java/io/xdag/net/message/p2p/InitMessageTest.java index f75af1912..d2392a562 100644 --- a/src/test/java/io/xdag/net/libp2p/discovery/DiscoveryNetworkTest.java +++ b/src/test/java/io/xdag/net/message/p2p/InitMessageTest.java @@ -21,29 +21,28 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +package io.xdag.net.message.p2p; -package io.xdag.net.libp2p.discovery; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; - -import io.xdag.utils.SafeFuture; import org.junit.Test; -public class DiscoveryNetworkTest { +import io.xdag.crypto.SecureRandomUtils; - private final DiscV5Service discoveryService = mock(DiscV5Service.class); +public class InitMessageTest { @Test - public void DiscoveryStart() { - final SafeFuture discoveryStart = new SafeFuture<>(); - doReturn(discoveryStart).when(discoveryService).start(); - } + public void testCodec() { + byte[] secret = SecureRandomUtils.secureRandom().generateSeed(32); + long timestamp = System.currentTimeMillis(); - @Test - @SuppressWarnings({"FutureReturnValueIgnored"}) - public void shouldStopNetworkAndDiscoveryWhenConnectionManagerStopFails() { - doReturn(new SafeFuture()).when(discoveryService).stop(); - } + InitMessage msg = new InitMessage(secret, timestamp); + assertArrayEquals(secret, msg.getSecret()); + assertEquals(timestamp, msg.getTimestamp()); + msg = new InitMessage(msg.getBody()); + assertArrayEquals(secret, msg.getSecret()); + assertEquals(timestamp, msg.getTimestamp()); + } } diff --git a/src/test/java/io/xdag/net/message/p2p/WorldMessageTest.java b/src/test/java/io/xdag/net/message/p2p/WorldMessageTest.java new file mode 100644 index 000000000..2b986ae96 --- /dev/null +++ b/src/test/java/io/xdag/net/message/p2p/WorldMessageTest.java @@ -0,0 +1,69 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020-2030 The XdagJ Developers + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package io.xdag.net.message.p2p; + +import static io.xdag.utils.WalletUtils.toBase58; +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.hyperledger.besu.crypto.KeyPair; +import org.junit.Test; + +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; +import io.xdag.crypto.Keys; +import io.xdag.crypto.SampleKeys; +import io.xdag.crypto.SecureRandomUtils; +import io.xdag.crypto.Sign; +import io.xdag.net.CapabilityTreeSet; +import io.xdag.net.Peer; + +public class WorldMessageTest { + + @Test + public void testCodec() { + Config config = new DevnetConfig(); + + KeyPair key = KeyPair.create(SampleKeys.SRIVATE_KEY, Sign.CURVE, Sign.CURVE_NAME); + String peerId = toBase58(Keys.toBytesAddress(key)); + WorldMessage msg = new WorldMessage(config.getNodeSpec().getNetwork(), config.getNodeSpec().getNetworkVersion(), peerId, 8001, + config.getClientId(), config.getClientCapabilities().toArray(), 2, + SecureRandomUtils.secureRandom().generateSeed(InitMessage.SECRET_LENGTH), key); + assertTrue(msg.validate(config)); + + msg = new WorldMessage(msg.getBody()); + assertTrue(msg.validate(config)); + + String ip = "127.0.0.2"; + Peer peer = msg.getPeer(ip); + assertEquals(config.getNodeSpec().getNetwork(), peer.getNetwork()); + assertEquals(config.getNodeSpec().getNetworkVersion(), peer.getNetworkVersion()); + assertEquals(toBase58(Keys.toBytesAddress(key)), peer.getPeerId()); + assertEquals(ip, peer.getIp()); + assertEquals(config.getNodeSpec().getNodePort(), peer.getPort()); + assertEquals(config.getClientId(), peer.getClientId()); + assertEquals(config.getClientCapabilities(), CapabilityTreeSet.of(peer.getCapabilities())); + assertEquals(2, peer.getLatestBlockNumber()); + } +} diff --git a/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java b/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java index b9194dcff..9486f14ce 100644 --- a/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java +++ b/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java @@ -73,7 +73,7 @@ public void setUp() throws Exception { wallet.setAccounts(Collections.singletonList(key)); wallet.flush(); - kernel = new Kernel(config); + kernel = new Kernel(config, key); dbFactory = new RocksdbFactory(config); BlockStore blockStore = new BlockStoreImpl( diff --git a/src/test/resources/xdag-devnet.conf b/src/test/resources/xdag-devnet.conf index bfa6bc3ea..b734b7004 100644 --- a/src/test/resources/xdag-devnet.conf +++ b/src/test/resources/xdag-devnet.conf @@ -3,35 +3,16 @@ admin.telnet.ip = 127.0.0.1 admin.telnet.port = 6001 admin.telnet.password = root -# Pool Config -pool.ip = 127.0.0.1 -pool.port = 7001 -pool.tag = XdagJ - -# Pool-Reward Config -pool.poolRation = 5 -pool.rewardRation = 5 -pool.fundRation = 5 -pool.directRation = 5 - # Node Config node.ip = 127.0.0.1 node.port = 8001 node.maxInboundConnectionsPerIp = 8 node.whiteIPs = ["127.0.0.1:8001","127.0.0.1:8002"] -node.libp2p.port = 9001 -node.libp2p.isbootnode = true -node.libp2p.privkey = 0x0802122074ca7d1380b2c407be6878669ebb5c7a2ee751bb18198f1a0f214bcb93b894b5 + node.transaction.history.pageSizeLimit = 888 # Node RPC Config rpc.enabled = true rpc.http.host = 127.0.0.1 rpc.http.port = 10001 -rpc.ws.port = 10002 - -# Miner Config -miner.globalMinerLimit = 8192 -miner.globalMinerChannelLimit = 8192 -miner.maxConnectPerIp = 256 -miner.maxMinerPerAccount = 256 \ No newline at end of file +rpc.ws.port = 10002 \ No newline at end of file