From 5a24600efcbef52d80d4f8b483a24aa3fa8df27e Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Thu, 13 May 2021 19:33:18 +0800 Subject: [PATCH 01/11] add rpc module, fix the signature problem --- pom.xml | 13 + src/main/java/io/xdag/Kernel.java | 89 ++++++ .../java/io/xdag/config/AbstractConfig.java | 46 +++ src/main/java/io/xdag/config/Config.java | 6 + .../java/io/xdag/config/RandomXConstants.java | 2 +- .../java/io/xdag/consensus/SyncManager.java | 2 +- src/main/java/io/xdag/consensus/XdagPow.java | 2 +- src/main/java/io/xdag/core/Block.java | 16 +- .../java/io/xdag/core/BlockchainImpl.java | 25 +- src/main/java/io/xdag/rpc/Web3.java | 88 ++++++ .../io/xdag/rpc/cors/CorsConfiguration.java | 29 ++ .../io/xdag/rpc/cors/OriginValidator.java | 109 +++++++ .../java/io/xdag/rpc/dto/BlockResultDTO.java | 20 ++ src/main/java/io/xdag/rpc/dto/StatusDTO.java | 10 + .../xdag/rpc/exception/XdagErrorResolver.java | 28 ++ .../XdagJsonRpcRequestException.java | 56 ++++ .../xdag/rpc/filter/JsonRpcMethodFilter.java | 41 +++ .../rpc/jsonrpc/JsonRpcBooleanResult.java | 35 +++ .../io/xdag/rpc/jsonrpc/JsonRpcError.java | 26 ++ .../rpc/jsonrpc/JsonRpcErrorResponse.java | 17 ++ .../jsonrpc/JsonRpcIdentifiableMessage.java | 27 ++ .../rpc/jsonrpc/JsonRpcInternalError.java | 7 + .../io/xdag/rpc/jsonrpc/JsonRpcMessage.java | 28 ++ .../io/xdag/rpc/jsonrpc/JsonRpcRequest.java | 22 ++ .../io/xdag/rpc/jsonrpc/JsonRpcResult.java | 8 + .../rpc/jsonrpc/JsonRpcResultOrError.java | 12 + .../rpc/jsonrpc/JsonRpcResultResponse.java | 17 ++ .../io/xdag/rpc/jsonrpc/JsonRpcVersion.java | 8 + .../java/io/xdag/rpc/jsonrpc/JsonUtils.java | 80 ++++++ .../xdag/rpc/modules/ModuleDescription.java | 89 ++++++ .../xdag/rpc/modules/XdagJsonRpcMethod.java | 10 + .../xdag/rpc/modules/XdagJsonRpcRequest.java | 28 ++ .../modules/XdagJsonRpcRequestVisitor.java | 12 + .../xdag/rpc/modules/debug/DebugModule.java | 30 ++ .../rpc/modules/debug/DebugModuleImpl.java | 81 ++++++ .../eth/subscribe/EthSubscribeParams.java | 12 + .../EthSubscribeParamsDeserializer.java | 60 ++++ .../subscribe/EthSubscribeParamsVisitor.java | 19 ++ .../eth/subscribe/EthSubscribeRequest.java | 48 ++++ .../eth/subscribe/EthUnsubscribeParams.java | 25 ++ .../eth/subscribe/EthUnsubscribeRequest.java | 49 ++++ .../modules/eth/subscribe/SubscriptionId.java | 52 ++++ .../xdag/rpc/modules/web3/Web3EthModule.java | 122 ++++++++ .../xdag/rpc/modules/web3/Web3XdagModule.java | 51 ++++ .../rpc/modules/web3/Web3XdagModuleImpl.java | 108 +++++++ .../io/xdag/rpc/modules/xdag/XdagModule.java | 49 ++++ .../rpc/modules/xdag/XdagModuleChain.java | 9 + .../rpc/modules/xdag/XdagModuleChainBase.java | 24 ++ .../modules/xdag/XdagModuleTransaction.java | 9 + .../xdag/XdagModuleTransactionBase.java | 43 +++ .../xdag/XdagModuleTransactionDisabled.java | 24 ++ .../rpc/modules/xdag/XdagModuleWallet.java | 8 + .../xdag/XdagModuleWalletDisabled.java | 28 ++ .../xdag/subscribe/XdagSubscribeParams.java | 15 + .../subscribe/XdagSubscribeParamsVisitor.java | 19 ++ .../XdagSubscriptionNotificationDTO.java | 4 + .../rpc/netty/JsonRpcWeb3FilterHandler.java | 128 +++++++++ .../rpc/netty/JsonRpcWeb3ServerHandler.java | 91 ++++++ .../netty/Web3HttpMethodFilterHandler.java | 37 +++ .../io/xdag/rpc/netty/Web3HttpServer.java | 97 +++++++ .../java/io/xdag/rpc/netty/Web3Result.java | 39 +++ .../netty/Web3ResultHttpResponseHandler.java | 50 ++++ .../Web3ResultWebSocketResponseHandler.java | 35 +++ .../xdag/rpc/netty/Web3WebSocketServer.java | 97 +++++++ .../io/xdag/rpc/netty/XdagJsonRpcHandler.java | 74 +++++ .../serialize/JacksonBasedRpcSerializer.java | 25 ++ .../xdag/rpc/serialize/JsonRpcSerializer.java | 23 ++ .../java/io/xdag/rpc/utils/HttpUtils.java | 24 ++ .../java/io/xdag/rpc/utils/TypeConverter.java | 132 +++++++++ src/main/java/io/xdag/utils/BasicAuth.java | 48 ++++ src/main/java/io/xdag/utils/BasicUtils.java | 18 ++ src/main/java/io/xdag/utils/Bytes.java | 271 ++++++++++++++++++ src/main/java/io/xdag/utils/BytesUtils.java | 37 +++ src/main/resources/log4j2.xml | 2 +- src/test/java/io/xdag/BlockBuilder.java | 4 +- .../java/io/xdag/core/BlockchainTest.java | 56 +++- .../java/io/xdag/core/RandomXSyncTest.java | 2 +- 77 files changed, 3157 insertions(+), 30 deletions(-) create mode 100644 src/main/java/io/xdag/rpc/Web3.java create mode 100644 src/main/java/io/xdag/rpc/cors/CorsConfiguration.java create mode 100644 src/main/java/io/xdag/rpc/cors/OriginValidator.java create mode 100644 src/main/java/io/xdag/rpc/dto/BlockResultDTO.java create mode 100644 src/main/java/io/xdag/rpc/dto/StatusDTO.java create mode 100644 src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java create mode 100644 src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java create mode 100644 src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java create mode 100644 src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java create mode 100644 src/main/java/io/xdag/rpc/modules/ModuleDescription.java create mode 100644 src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java create mode 100644 src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java create mode 100644 src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java create mode 100644 src/main/java/io/xdag/rpc/modules/debug/DebugModule.java create mode 100644 src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParams.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsDeserializer.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsVisitor.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeRequest.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeParams.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeRequest.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/subscribe/SubscriptionId.java create mode 100644 src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java create mode 100644 src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java create mode 100644 src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java create mode 100644 src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java create mode 100644 src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3HttpServer.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3Result.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java create mode 100644 src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java create mode 100644 src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java create mode 100644 src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java create mode 100644 src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java create mode 100644 src/main/java/io/xdag/rpc/utils/HttpUtils.java create mode 100644 src/main/java/io/xdag/rpc/utils/TypeConverter.java create mode 100644 src/main/java/io/xdag/utils/BasicAuth.java create mode 100644 src/main/java/io/xdag/utils/Bytes.java diff --git a/pom.xml b/pom.xml index 3a02dc6d..e1f89792 100644 --- a/pom.xml +++ b/pom.xml @@ -568,6 +568,19 @@ 2.12.2 + + + com.github.briandilley.jsonrpc4j + jsonrpc4j + 1.6 + + + slf4j-api + org.slf4j + + + + diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 7a7fd58d..05570b2b 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -59,12 +59,20 @@ import io.xdag.net.message.NetDB; import io.xdag.net.node.NodeManager; import io.xdag.randomx.RandomX; +import io.xdag.rpc.Web3; +import io.xdag.rpc.cors.CorsConfiguration; +import io.xdag.rpc.modules.web3.Web3XdagModuleImpl; +import io.xdag.rpc.netty.*; +import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; +import io.xdag.rpc.serialize.JsonRpcSerializer; import io.xdag.utils.XdagTime; import io.xdag.wallet.OldWallet; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -115,6 +123,14 @@ public class Kernel { protected long startEpoch; + // rpc + protected JsonRpcWeb3ServerHandler jsonRpcWeb3ServerHandler; + protected Web3 web3; +// protected Web3WebSocketServer web3WebSocketServer; + protected Web3HttpServer web3HttpServer; + protected JsonRpcWeb3FilterHandler jsonRpcWeb3FilterHandler; + protected JacksonBasedRpcSerializer jacksonBasedRpcSerializer; + public Kernel(Config config, OldWallet wallet) { this.config = config; this.wallet = wallet; @@ -287,6 +303,79 @@ public synchronized void testStart() throws Exception { Launcher.registerShutdownHook("kernel", this::testStop); } + private Web3 getWeb3() { + if (web3 == null) { + web3 = buildWeb3(); + } + + return web3; + } + + private Web3 buildWeb3() { + return null; + } + + private JsonRpcWeb3ServerHandler getJsonRpcWeb3ServerHandler() { + if (jsonRpcWeb3ServerHandler == null) { + jsonRpcWeb3ServerHandler = new JsonRpcWeb3ServerHandler( + getWeb3(), + config.getRpcModules() + ); + } + + return jsonRpcWeb3ServerHandler; + } +// +// private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException { +// if (web3WebSocketServer == null) { +// JsonRpcSerializer jsonRpcSerializer = getJsonRpcSerializer(); +// XdagJsonRpcHandler jsonRpcHandler = new XdagJsonRpcHandler(jsonRpcSerializer); +// web3WebSocketServer = new Web3WebSocketServer( +// InetAddress.getLocalHost(), +// 4444, +// jsonRpcHandler, +// getJsonRpcWeb3ServerHandler() +// ); +// } +// +// return web3WebSocketServer; +// } + + private Web3HttpServer getWeb3HttpServer() throws UnknownHostException { + if (web3HttpServer == null) { + web3HttpServer = new Web3HttpServer( + InetAddress.getLocalHost(), + 4445, + 123, + true, + new CorsConfiguration("*"), + getJsonRpcWeb3FilterHandler(), + getJsonRpcWeb3ServerHandler() + ); + } + + return web3HttpServer; + } + + private JsonRpcWeb3FilterHandler getJsonRpcWeb3FilterHandler() throws UnknownHostException { + if (jsonRpcWeb3FilterHandler == null) { + jsonRpcWeb3FilterHandler = new JsonRpcWeb3FilterHandler( + "*", + InetAddress.getLocalHost(), + null + ); + } + + return jsonRpcWeb3FilterHandler; + } + + private JsonRpcSerializer getJsonRpcSerializer() { + if (jacksonBasedRpcSerializer == null) { + jacksonBasedRpcSerializer = new JacksonBasedRpcSerializer(); + } + + return jacksonBasedRpcSerializer; + } /** Stops the kernel. */ public synchronized void testStop() { diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index 9cf371f3..ca335da2 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -30,6 +30,7 @@ import io.xdag.crypto.jni.Native; import io.xdag.discovery.peers.DiscoveryPeer; import io.xdag.discovery.peers.Endpoint; +import io.xdag.rpc.modules.ModuleDescription; import io.xdag.utils.discoveryutils.bytes.BytesValue; import lombok.Getter; import lombok.Setter; @@ -133,6 +134,12 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa protected long apolloForkAmount; + // ========================= + // Xdag RPC modules + // ========================= + protected List moduleDescriptions; + + public void setDir() { storeDir = getRootDir() + "/rocksdb/xdagdb"; storeBackupDir = getRootDir() + "/rocksdb/xdagdb/backupdata"; @@ -324,4 +331,43 @@ public void setDnetKeyBytes(byte[] dnetKeyBytes) { public boolean enableRefresh() { return this.enableRefresh; } + + @Override + public List getRpcModules() { + if (this.moduleDescriptions != null) { + return this.moduleDescriptions; + } + + List modules = new ArrayList<>(); + + // TODO: get modules from config +// if (!configFromFiles.hasPath("rpc.modules")) { +// return modules; +// } +// +// List list = configFromFiles.getObjectList("rpc.modules"); +// +// for (ConfigObject configObject : list) { +// Config configElement = configObject.toConfig(); +// String name = configElement.getString("name"); +// String version = configElement.getString("version"); +// boolean enabled = configElement.getBoolean("enabled"); +// List enabledMethods = null; +// List disabledMethods = null; +// +// if (configElement.hasPath("methods.enabled")) { +// enabledMethods = configElement.getStringList("methods.enabled"); +// } +// +// if (configElement.hasPath("methods.disabled")) { +// disabledMethods = configElement.getStringList("methods.disabled"); +// } +// +// modules.add(new ModuleDescription(name, version, enabled, enabledMethods, disabledMethods)); +// } + + this.moduleDescriptions = modules; + + return modules; + } } diff --git a/src/main/java/io/xdag/config/Config.java b/src/main/java/io/xdag/config/Config.java index 017a8dde..41f77121 100644 --- a/src/main/java/io/xdag/config/Config.java +++ b/src/main/java/io/xdag/config/Config.java @@ -28,6 +28,9 @@ import io.xdag.config.spec.NodeSpec; import io.xdag.config.spec.WalletSpec; import io.xdag.core.XdagField; +import io.xdag.rpc.modules.ModuleDescription; + +import java.util.List; /** * The Xdag blockchain configurations. @@ -78,4 +81,7 @@ public interface Config { void setDir(); void initKeys() throws Exception; + // rpc + List getRpcModules(); + } diff --git a/src/main/java/io/xdag/config/RandomXConstants.java b/src/main/java/io/xdag/config/RandomXConstants.java index 4c24e795..3137045a 100644 --- a/src/main/java/io/xdag/config/RandomXConstants.java +++ b/src/main/java/io/xdag/config/RandomXConstants.java @@ -32,7 +32,7 @@ public class RandomXConstants { public static long SEEDHASH_EPOCH_TESTNET_LAG = 64; public static final long RANDOMX_FORK_HEIGHT = 1540096; - public static long RANDOMX_TESTNET_FORK_HEIGHT = 4096;// 196288 + public static long RANDOMX_TESTNET_FORK_HEIGHT = 40960000000L;// 196288 public static final int XDAG_RANDOMX = 2; diff --git a/src/main/java/io/xdag/consensus/SyncManager.java b/src/main/java/io/xdag/consensus/SyncManager.java index 47a43d00..4f7cf122 100644 --- a/src/main/java/io/xdag/consensus/SyncManager.java +++ b/src/main/java/io/xdag/consensus/SyncManager.java @@ -155,7 +155,7 @@ public boolean isTimeToStart() { //todo:修改共识 public ImportResult importBlock(BlockWrapper blockWrapper) { log.debug("importBlock:{}", BytesUtils.toHexString(blockWrapper.getBlock().getHash())); - ImportResult importResult = blockchain.tryToConnect(blockWrapper.getBlock()); + ImportResult importResult = blockchain.tryToConnect(new Block(new XdagBlock(blockWrapper.getBlock().getXdagBlock().getData()))); if (importResult == EXIST) { log.error("Block have exist:" + Hex.toHexString(blockWrapper.getBlock().getHash())); diff --git a/src/main/java/io/xdag/consensus/XdagPow.java b/src/main/java/io/xdag/consensus/XdagPow.java index a8e6ebcb..4fd6f9a5 100644 --- a/src/main/java/io/xdag/consensus/XdagPow.java +++ b/src/main/java/io/xdag/consensus/XdagPow.java @@ -134,7 +134,7 @@ public void stop() { } public void newBlock() { - log.debug("Start new block generate...."); + log.info("Start new block generate...."); long sendTime = XdagTime.getMainTime(); resetTimeout(sendTime); diff --git a/src/main/java/io/xdag/core/Block.java b/src/main/java/io/xdag/core/Block.java index 2f88cb49..da587cef 100644 --- a/src/main/java/io/xdag/core/Block.java +++ b/src/main/java/io/xdag/core/Block.java @@ -351,7 +351,7 @@ private void sign(ECKeyPair ecKey, XdagField.FieldType type) { if (type == XDAG_FIELD_SIGN_OUT) { outsig = signature; } else { - insigs.put(signature, tempLength + 1); + insigs.put(signature, tempLength); } } @@ -362,11 +362,11 @@ public List verifiedKeys() { byte[] digest; byte[] hash; for (ECDSASignature sig : this.getInsigs().keySet()) { - digest = getSubRawData(this.getInsigs().get(sig) - 2); + digest = getSubRawData(this.getInsigs().get(sig) - 1); for (ECKeyPair ecKey : keys) { byte[] pubkeyBytes = ECKeyPair.compressPubKey(ecKey.getPublicKey()); hash = Hash.hashTwice(BytesUtils.merge(digest, pubkeyBytes)); - if (ECKeyPair.verify(hash, sig, pubkeyBytes)) { + if (ECKeyPair.verify(hash, sig.toCanonicalised(), pubkeyBytes)) { res.add(ecKey); } } @@ -376,7 +376,7 @@ public List verifiedKeys() { byte[] pubkeyBytes = ECKeyPair.compressPubKey(ecKey.getPublicKey()); hash = Hash.hashTwice(BytesUtils.merge(digest, pubkeyBytes)); - if (ECKeyPair.verify(hash, this.getOutsig(),pubkeyBytes)) { + if (ECKeyPair.verify(hash, this.getOutsig().toCanonicalised(),pubkeyBytes)) { res.add(ecKey); } } @@ -470,6 +470,14 @@ public byte[] getSubRawData(int length) { byte[] data = getXdagBlock().getData(); byte[] res = new byte[512]; System.arraycopy(data, 0, res, 0, (length + 1) * 32); + for (int i = length+1; i < 16; i++) { + long type = BytesUtils.bytesToLong(data, 8, true); + byte typeB = (byte) (type >> (i << 2) & 0xf); + if (XDAG_FIELD_SIGN_IN.asByte() == typeB || XDAG_FIELD_SIGN_OUT.asByte() == typeB) { + continue; + } + System.arraycopy(data, (i) * 32, res, (i) * 32, 32); + } return res; } diff --git a/src/main/java/io/xdag/core/BlockchainImpl.java b/src/main/java/io/xdag/core/BlockchainImpl.java index 5812c752..bfd1eb4a 100644 --- a/src/main/java/io/xdag/core/BlockchainImpl.java +++ b/src/main/java/io/xdag/core/BlockchainImpl.java @@ -517,8 +517,8 @@ private UnsignedLong applyBlock(Block block) { continue; } updateBlockRef(ref, new Address(block)); - if (amount2xdag(UnsignedLong.valueOf(block.getInfo().getAmount()).plus(ret).longValue()) >= amount2xdag( - block.getInfo().getAmount())) { + if (UnsignedLong.valueOf(block.getInfo().getAmount()).plus(ret).longValue() >= + block.getInfo().getAmount()) { acceptAmount(block, ret); } } @@ -527,18 +527,18 @@ private UnsignedLong applyBlock(Block block) { if (link.getType() == XdagField.FieldType.XDAG_FIELD_IN) { Block ref = getBlockByHash(link.getHashLow(), false); - if (amount2xdag(ref.getInfo().getAmount()) < amount2xdag(link.getAmount().longValue())) { + if (ref.getInfo().getAmount() < link.getAmount().longValue()) { log.debug("This input ref doesn't have enough amount,hash:{},amount:{},need:{}",Hex.toHexString(ref.getInfo().getHashlow()),ref.getInfo().getAmount(), link.getAmount().longValue()); return UnsignedLong.ZERO; } - if (amount2xdag(sumIn.plus(UnsignedLong.valueOf(link.getAmount())).longValue()) < amount2xdag(sumIn.longValue())) { + if (sumIn.plus(UnsignedLong.valueOf(link.getAmount())).longValue() < sumIn.longValue()) { log.debug("This input ref's amount less than 0"); return UnsignedLong.ZERO; } sumIn = sumIn.plus(UnsignedLong.valueOf(link.getAmount())); } else { - if (amount2xdag(sumOut.plus(UnsignedLong.valueOf(link.getAmount())).longValue()) < amount2xdag(sumOut.longValue())) { + if (sumOut.plus(UnsignedLong.valueOf(link.getAmount())).longValue() < sumOut.longValue()) { log.debug("This output ref's amount less than 0"); return UnsignedLong.ZERO; } @@ -546,8 +546,8 @@ private UnsignedLong applyBlock(Block block) { } } - if (amount2xdag(UnsignedLong.valueOf(block.getInfo().getAmount()).plus(sumIn).longValue()) < amount2xdag(sumOut.longValue()) - || amount2xdag(UnsignedLong.valueOf(block.getInfo().getAmount()).plus(sumIn).longValue()) < amount2xdag(sumIn.longValue())) { + if (UnsignedLong.valueOf(block.getInfo().getAmount()).plus(sumIn).longValue() < sumOut.longValue() + || UnsignedLong.valueOf(block.getInfo().getAmount()).plus(sumIn).longValue() < sumIn.longValue()) { log.debug("exec fail!"); return UnsignedLong.ZERO; } @@ -1116,21 +1116,12 @@ public boolean canUseInput(Block block) { byte[] digest = BytesUtils.merge(subdata, publicKeyBytes); // log.debug("verify encoded:{}", Hex.toHexString(digest)); byte[] hash = Hash.hashTwice(digest); - if (ECKeyPair.verify(hash, sig, publicKeyBytes)) { + if (ECKeyPair.verify(hash, sig.toCanonicalised(), publicKeyBytes)) { canUse = true; } } if (!canUse) { - //TODO this maybe some old issue( input and output was same ) - List keys = block.getPubKeys(); - for (ECKeyPair ecKey : keys) { - byte[] publicKeyBytes = ECKeyPair.compressPubKey(ecKey.getPublicKey()); - byte[] hash = Hash.hashTwice(BytesUtils.merge(subdata, publicKeyBytes)); - if (ECKeyPair.verify(hash, sig, publicKeyBytes)) { - return true; - } - } return false; } } diff --git a/src/main/java/io/xdag/rpc/Web3.java b/src/main/java/io/xdag/rpc/Web3.java new file mode 100644 index 00000000..a5b7e56e --- /dev/null +++ b/src/main/java/io/xdag/rpc/Web3.java @@ -0,0 +1,88 @@ +package io.xdag.rpc; + +import java.util.Arrays; +import java.util.Map; + +public interface Web3 { + class CallArguments { + public String from; + public String to; +// public String gas; +// public String gasPrice; + public String value; +// public String data; // compiledCode + public String remark; + public String netType; +// public String nonce; + public String chainId; //NOSONAR + + @Override + public String toString() { + return "CallArguments{" + + "from='" + from + '\'' + + ", to='" + to + '\'' + +// ", gasLimit='" + gas + '\'' + +// ", gasPrice='" + gasPrice + '\'' + + ", value='" + value + '\'' + + ", remark='" + remark + '\'' + + ", netType='" + netType + '\'' + +// ", data='" + data + '\'' + +// ", nonce='" + nonce + '\'' + + ", chainId='" + chainId + '\'' + + '}'; + } + } + + class BlockInformationResult { + public String hash; + public String totalDifficulty; + public boolean inMainChain; + } + + class FilterRequest { + public String fromBlock; + public String toBlock; + public Object address; + public Object[] topics; + + @Override + public String toString() { + return "FilterRequest{" + + "fromBlock='" + fromBlock + '\'' + + ", toBlock='" + toBlock + '\'' + + ", address=" + address + + ", topics=" + Arrays.toString(topics) + + '}'; + } + } + + String web3_clientVersion(); + String web3_sha3(String data) throws Exception; + String net_version(); + String net_peerCount(); + boolean net_listening(); + String[] net_peerList(); + + // methods required by dev environments + Map rpc_modules(); + + void db_putString(); + void db_getString(); + + void db_putHex(); + void db_getHex(); + + String personal_newAccount(String passphrase); + String[] personal_listAccounts(); + String personal_importRawKey(String key, String passphrase); + String personal_sendTransaction(CallArguments transactionArgs, String passphrase) throws Exception; + boolean personal_unlockAccount(String key, String passphrase, String duration); + boolean personal_lockAccount(String key); + String personal_dumpRawKey(String address) throws Exception; + +// void sco_banAddress(String address); +// void sco_unbanAddress(String address); +// PeerScoringInformation[] sco_peerList(); +// String[] sco_bannedAddresses(); +// PeerScoringReputationSummary sco_reputationSummary(); +} diff --git a/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java b/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java new file mode 100644 index 00000000..465b914b --- /dev/null +++ b/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java @@ -0,0 +1,29 @@ +package io.xdag.rpc.cors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CorsConfiguration { + private static final Logger logger = LoggerFactory.getLogger("cors"); + private final String header; + + public CorsConfiguration(String header) { + this.header = header; + + if ("*".equals(header)) { + logger.warn("CORS header set to '*'"); + } + + if (header != null && (header.contains("\n") || header.contains("\r"))) { + throw new IllegalArgumentException("corsheader"); + } + } + + public String getHeader() { + return this.header; + } + + public boolean hasHeader() { + return this.header != null && this.header.length() != 0; + } +} diff --git a/src/main/java/io/xdag/rpc/cors/OriginValidator.java b/src/main/java/io/xdag/rpc/cors/OriginValidator.java new file mode 100644 index 00000000..71e9d32b --- /dev/null +++ b/src/main/java/io/xdag/rpc/cors/OriginValidator.java @@ -0,0 +1,109 @@ +package io.xdag.rpc.cors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nonnull; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +public class OriginValidator { + private static final Logger LOGGER = LoggerFactory.getLogger("jsonrpc"); + + private URI[] origins; + private boolean allowAllOrigins; + + public OriginValidator() { + this.origins = new URI[0]; + } + + public OriginValidator(String uriList) { + if (uriList == null) { + this.origins = new URI[0]; + } else if ("*".equals(uriList.trim())) { + this.allowAllOrigins = true; + } else { + try { + this.origins = toUris(uriList); + } catch (URISyntaxException e) { + LOGGER.error("Error creating OriginValidator, origins {}, {}", uriList, e); + + // no origin + this.origins = new URI[0]; + } + } + } + + public boolean isValidOrigin(String origin) { + if (this.allowAllOrigins) { + return true; + } + + URI originUri = null; + + try { + originUri = new URI(origin); + } catch (URISyntaxException e) { + return false; + } + + for (URI uri : origins) { + if (originUri.equals(uri)) { + return true; + } + } + + return false; + } + + public boolean isValidReferer(String referer) { + if (this.allowAllOrigins) { + return true; + } + + URL refererUrl = null; + + try { + refererUrl = new URL(referer); + } catch (MalformedURLException e) { + return false; + } + + String refererProtocol = refererUrl.getProtocol(); + + if (refererProtocol == null) { + return false; + } + + String refererHost = refererUrl.getHost(); + + if (refererHost == null) { + return false; + } + + int refererPort = refererUrl.getPort(); + + for (int k = 0; k < origins.length; k++) { + if (refererProtocol.equals(origins[k].getScheme()) && + refererHost.equals(origins[k].getHost()) && + refererPort == origins[k].getPort()) { + return true; + } + } + + return false; + } + + private static URI[] toUris(@Nonnull String list) throws URISyntaxException { + String[] elements = list.split(" "); + URI[] uris = new URI[elements.length]; + + for (int k = 0; k < elements.length; k++) { + uris[k] = new URI(elements[k].trim()); + } + + return uris; + } +} diff --git a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java new file mode 100644 index 00000000..301effdc --- /dev/null +++ b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java @@ -0,0 +1,20 @@ +package io.xdag.rpc.dto; + + +import io.xdag.core.Block; +import lombok.Data; + +@Data +public class BlockResultDTO { + + // blockInfo + // rawData + + + + public static BlockResultDTO fromBlock(Block b, boolean raw) { + + + return null; + } +} diff --git a/src/main/java/io/xdag/rpc/dto/StatusDTO.java b/src/main/java/io/xdag/rpc/dto/StatusDTO.java new file mode 100644 index 00000000..97b09ce2 --- /dev/null +++ b/src/main/java/io/xdag/rpc/dto/StatusDTO.java @@ -0,0 +1,10 @@ +package io.xdag.rpc.dto; + +public class StatusDTO { + // status 状态信息 + // host + // nblocks + // nmain + // diff + +} diff --git a/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java b/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java new file mode 100644 index 00000000..6838cecb --- /dev/null +++ b/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java @@ -0,0 +1,28 @@ +package io.xdag.rpc.exception; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import com.googlecode.jsonrpc4j.ErrorResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Method; +import java.util.List; + +public class XdagErrorResolver implements ErrorResolver{ + private static final Logger logger = LoggerFactory.getLogger("web3"); + + @Override + public ErrorResolver.JsonError resolveError(Throwable t, Method method, List arguments) { + ErrorResolver.JsonError error = null; + if(t instanceof XdagJsonRpcRequestException) { + error = new ErrorResolver.JsonError(((XdagJsonRpcRequestException) t).getCode(), t.getMessage(), null); + } else if (t instanceof InvalidFormatException) { + error = new ErrorResolver.JsonError(-32603, "Internal server error, probably due to invalid parameter type", null); + } else { + logger.error("JsonRPC error when for method {} with arguments {}", method, arguments, t); + error = new ErrorResolver.JsonError(-32603, "Internal server error", null); + } + return error; + } +} diff --git a/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java b/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java new file mode 100644 index 00000000..a2c574e8 --- /dev/null +++ b/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java @@ -0,0 +1,56 @@ +package io.xdag.rpc.exception; + +public class XdagJsonRpcRequestException extends RuntimeException { + + private final Integer code; + + protected XdagJsonRpcRequestException(Integer code, String message, Exception e) { + super(message, e); + this.code = code; + } + + public XdagJsonRpcRequestException(Integer code, String message) { + super(message); + this.code = code; + } + + public Integer getCode() { + return code; + } + + public static XdagJsonRpcRequestException transactionRevertedExecutionError() { + return executionError("transaction reverted"); + } + + public static XdagJsonRpcRequestException unknownError(String message) { + return new XdagJsonRpcRequestException(-32009, message); + } + + private static XdagJsonRpcRequestException executionError(String message) { + return new XdagJsonRpcRequestException(-32015, String.format("VM execution error: %s", message)); + } + + public static XdagJsonRpcRequestException transactionError(String message) { + return new XdagJsonRpcRequestException(-32010, message); + } + + public static XdagJsonRpcRequestException invalidParamError(String message) { + return new XdagJsonRpcRequestException(-32602, message); + } + + public static XdagJsonRpcRequestException invalidParamError(String message, Exception e) { + return new XdagJsonRpcRequestException(-32602, message, e); + } + + public static XdagJsonRpcRequestException unimplemented(String message) { + return new XdagJsonRpcRequestException(-32201, message); + } + + public static XdagJsonRpcRequestException blockNotFound(String message) { + return new XdagJsonRpcRequestException(-32600, message); + } + + public static XdagJsonRpcRequestException stateNotFound(String message) { + return new XdagJsonRpcRequestException(-32600, message); + } +} diff --git a/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java b/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java new file mode 100644 index 00000000..0f5d2065 --- /dev/null +++ b/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java @@ -0,0 +1,41 @@ +package io.xdag.rpc.filter; + +import com.fasterxml.jackson.databind.JsonNode; +import com.googlecode.jsonrpc4j.JsonRpcBasicServer; +import com.googlecode.jsonrpc4j.RequestInterceptor; +import io.xdag.rpc.modules.ModuleDescription; + +import java.io.IOException; +import java.util.List; + +public class JsonRpcMethodFilter implements RequestInterceptor { + + private List modules; + + /** + * This checks the JSON RPC invoked method against the received list of modules + * + * + * @param modules list of configured modules + */ + public JsonRpcMethodFilter(List modules) { + this.modules = modules; + } + + @Override + public void interceptRequest(JsonNode node) throws IOException { + if (node.hasNonNull(JsonRpcBasicServer.METHOD)) { + checkMethod(node.get(JsonRpcBasicServer.METHOD).asText()); + } + } + + private void checkMethod(String methodName) throws IOException { + for (ModuleDescription module: this.modules) { + if (module.methodIsEnable(methodName)) { + return; + } + } + + throw new IOException("Method not supported: " + methodName); + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java new file mode 100644 index 00000000..141f4c48 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java @@ -0,0 +1,35 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonValue; + +public class JsonRpcBooleanResult extends JsonRpcResult { + private final boolean result; + + public JsonRpcBooleanResult(boolean result) { + this.result = result; + } + + @JsonValue + public boolean getResult() { + return result; + } + + @Override + public int hashCode() { + return Boolean.hashCode(result); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof JsonRpcBooleanResult)) { + return false; + } + + JsonRpcBooleanResult other = (JsonRpcBooleanResult) o; + return this.result == other.result; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java new file mode 100644 index 00000000..57cd72b1 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java @@ -0,0 +1,26 @@ +package io.xdag.rpc.jsonrpc; + +import java.util.Objects; + +public class JsonRpcError implements JsonRpcResultOrError { + private final int code; + private final String message; + + public JsonRpcError(int code, String message) { + this.code = code; + this.message = Objects.requireNonNull(message); + } + + public String getMessage() { + return message; + } + + public int getCode() { + return code; + } + + @Override + public JsonRpcIdentifiableMessage responseFor(int messageId) { + return new JsonRpcErrorResponse(messageId, this); + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java new file mode 100644 index 00000000..6f545da2 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java @@ -0,0 +1,17 @@ +package io.xdag.rpc.jsonrpc; + +import java.util.Objects; + +public class JsonRpcErrorResponse extends JsonRpcIdentifiableMessage { + private final JsonRpcError error; + + public JsonRpcErrorResponse(int id, JsonRpcError error) { + super(JsonRpcVersion.V2_0, id); + this.error = Objects.requireNonNull(error); + } + + @SuppressWarnings("unused") + public JsonRpcError getError() { + return error; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java new file mode 100644 index 00000000..7eeb9250 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java @@ -0,0 +1,27 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonInclude; + +public abstract class JsonRpcIdentifiableMessage extends JsonRpcMessage{ + private final int id; + + public JsonRpcIdentifiableMessage(JsonRpcVersion version, int id) { + super(version); + this.id = requireNonNegative(id); + } + + @JsonInclude(JsonInclude.Include.ALWAYS) + public int getId() { + return id; + } + + private static int requireNonNegative(int id) { + if (id < 0) { + throw new IllegalArgumentException( + String.format("JSON-RPC message id should be a positive number, but was %s.", id) + ); + } + + return id; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java new file mode 100644 index 00000000..c6e5a878 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java @@ -0,0 +1,7 @@ +package io.xdag.rpc.jsonrpc; + +public class JsonRpcInternalError extends JsonRpcError { + public JsonRpcInternalError() { + super(-32603, "Internal error."); + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java new file mode 100644 index 00000000..780fa500 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java @@ -0,0 +1,28 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +public abstract class JsonRpcMessage { + private final JsonRpcVersion version; + + public JsonRpcMessage(JsonRpcVersion version) { + this.version = verifyVersion(version); + } + + @JsonProperty("jsonrpc") + @JsonInclude(JsonInclude.Include.ALWAYS) + public JsonRpcVersion getVersion() { + return version; + } + + private static JsonRpcVersion verifyVersion(JsonRpcVersion version) { + if (version != JsonRpcVersion.V2_0) { + throw new IllegalArgumentException( + String.format("JSON-RPC version should always be %s, but was %s.", JsonRpcVersion.V2_0, version) + ); + } + + return version; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java new file mode 100644 index 00000000..d5b89b4c --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java @@ -0,0 +1,22 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.Objects; + +public abstract class JsonRpcRequest> extends JsonRpcIdentifiableMessage { + private final T method; + + public JsonRpcRequest( + JsonRpcVersion version, + T method, + int id) { + super(version, id); + this.method = Objects.requireNonNull(method); + } + + @JsonInclude(JsonInclude.Include.ALWAYS) + public T getMethod() { + return method; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java new file mode 100644 index 00000000..edba8184 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java @@ -0,0 +1,8 @@ +package io.xdag.rpc.jsonrpc; + +public abstract class JsonRpcResult implements JsonRpcResultOrError{ + @Override + public JsonRpcIdentifiableMessage responseFor(int messageId) { + return new JsonRpcResultResponse(messageId, this); + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java new file mode 100644 index 00000000..f2a84e1a --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java @@ -0,0 +1,12 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public interface JsonRpcResultOrError { + /** + * @return a response according to the result or error state of this object. + * @param messageId the message ID + */ + @JsonIgnore + JsonRpcIdentifiableMessage responseFor(int messageId); +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java new file mode 100644 index 00000000..45a17842 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java @@ -0,0 +1,17 @@ +package io.xdag.rpc.jsonrpc; + +import java.util.Objects; + +public class JsonRpcResultResponse extends JsonRpcIdentifiableMessage { + private final JsonRpcResult result; + + public JsonRpcResultResponse(int id, JsonRpcResult result) { + super(JsonRpcVersion.V2_0, id); + this.result = Objects.requireNonNull(result); + } + + @SuppressWarnings("unused") + public JsonRpcResult getResult() { + return result; + } +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java new file mode 100644 index 00000000..39c50a47 --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java @@ -0,0 +1,8 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum JsonRpcVersion { + @JsonProperty("2.0") + V2_0, +} diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java new file mode 100644 index 00000000..013b418d --- /dev/null +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java @@ -0,0 +1,80 @@ +package io.xdag.rpc.jsonrpc; + +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; + +import static io.xdag.utils.BasicUtils.unifiedNumericToBigInteger; +import static io.xdag.utils.BytesUtils.EMPTY_BYTE_ARRAY; +import static io.xdag.utils.BytesUtils.stripLeadingZeroes; + +public class JsonUtils { + public static byte[] parseVarData(String data){ + if (data == null || data.equals("")) { + return EMPTY_BYTE_ARRAY; + } + if (data.startsWith("0x")) { + data = data.substring(2); + if (data.equals("")) { + return EMPTY_BYTE_ARRAY; + } + + if (data.length() % 2 == 1) { + data = "0" + data; + } + + return Hex.decode(data); + } + + return parseNumericData(data); + } + + + public static byte[] parseData(String data) { + if (data == null) { + return EMPTY_BYTE_ARRAY; + } + if (data.startsWith("0x")) { + data = data.substring(2); + } + return Hex.decode(data); + } + + public static byte[] parseNumericData(String data){ + + if (data == null || data.equals("")) { + return EMPTY_BYTE_ARRAY; + } + byte[] dataB = unifiedNumericToBigInteger(data).toByteArray(); + return stripLeadingZeroes(dataB); + } + + public static long parseLong(String data) { + boolean hex = data.startsWith("0x"); + if (hex) { + data = data.substring(2); + } + if (data.equals("")) { + return 0; + } + return new BigInteger(data, hex ? 16 : 10).longValue(); + } + + public static byte parseByte(String data) { + if (data.startsWith("0x")) { + data = data.substring(2); + return data.equals("") ? 0 : Byte.parseByte(data, 16); + } else { + return data.equals("") ? 0 : Byte.parseByte(data); + } + } + + + public static String parseUnidentifiedBase(String number) { + if (number.startsWith("0x")) { + number = new BigInteger(number.substring(2), 16).toString(10); + } + return number; + } +} + diff --git a/src/main/java/io/xdag/rpc/modules/ModuleDescription.java b/src/main/java/io/xdag/rpc/modules/ModuleDescription.java new file mode 100644 index 00000000..088a4e73 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/ModuleDescription.java @@ -0,0 +1,89 @@ +package io.xdag.rpc.modules; + +import java.util.ArrayList; +import java.util.List; + +public class ModuleDescription { + private String name; + private String version; + private boolean enabled; + + private List enabledMethods; + private List disabledMethods; + + public ModuleDescription(String name, String version, boolean enabled, List enabledMethods, List disabledMethods) { + this.name = name; + this.version = version; + this.enabled = enabled; + this.enabledMethods = enabledMethods == null ? new ArrayList<>() : enabledMethods; + this.disabledMethods = disabledMethods == null ? new ArrayList<>() : disabledMethods; + } + + public String getName() { + return this.name; + } + + public String getVersion() { + return this.version; + } + + public boolean isEnabled() { + return this.enabled; + } + + public List getEnabledMethods() { + return this.enabledMethods; + } + + public List getDisabledMethods() { + return this.disabledMethods; + } + + public boolean methodIsInModule(String methodName) { + if (methodName == null) { + return false; + } + + if (!methodName.startsWith(this.name)) { + return false; + } + + if (methodName.length() == this.name.length()) { + return false; + } + + if (methodName.charAt(this.name.length()) != '_') { + return false; + } + + return true; + } + + public boolean methodIsEnable(String methodName) { + if (!this.isEnabled()) { + return false; + } + + if (!this.methodIsInModule(methodName)) { + return false; + } + + if (this.disabledMethods.contains(methodName)) { + return false; + } + + if (this.enabledMethods.isEmpty() && this.disabledMethods.isEmpty()) { + return true; + } + + if (this.enabledMethods.contains(methodName)) { + return true; + } + + if (!this.enabledMethods.isEmpty()) { + return false; + } + + return true; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java new file mode 100644 index 00000000..78348961 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java @@ -0,0 +1,10 @@ +package io.xdag.rpc.modules; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum XdagJsonRpcMethod { + @JsonProperty("eth_subscribe") + ETH_SUBSCRIBE, + @JsonProperty("eth_unsubscribe") + ETH_UNSUBSCRIBE +} diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java new file mode 100644 index 00000000..f8fc1b85 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java @@ -0,0 +1,28 @@ +package io.xdag.rpc.modules; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.netty.channel.ChannelHandlerContext; +import io.xdag.rpc.jsonrpc.JsonRpcRequest; +import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +import io.xdag.rpc.jsonrpc.JsonRpcVersion; + + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "method", visible = true) +@JsonSubTypes({ +// @JsonSubTypes.Type(value = EthSubscribeRequest.class, name = "eth_subscribe"), +// @JsonSubTypes.Type(value = EthUnsubscribeRequest.class, name = "eth_unsubscribe"), +}) +public abstract class XdagJsonRpcRequest extends JsonRpcRequest { + public XdagJsonRpcRequest( + JsonRpcVersion version, + XdagJsonRpcMethod method, + int id) { + super(version, method, id); + } + + /** + * Inheritors should implement this method by delegating to the corresponding visitor method. + */ + public abstract JsonRpcResultOrError accept(XdagJsonRpcRequestVisitor visitor, ChannelHandlerContext ctx); +} diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java new file mode 100644 index 00000000..1c76a274 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java @@ -0,0 +1,12 @@ +package io.xdag.rpc.modules; + +import io.netty.channel.ChannelHandlerContext; +import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +//import io.xdag.rpc.modules.eth.subscribe.EthSubscribeRequest; +//import io.xdag.rpc.modules.eth.subscribe.EthUnsubscribeRequest; + +public interface XdagJsonRpcRequestVisitor { +// JsonRpcResultOrError visit(EthUnsubscribeRequest request, ChannelHandlerContext ctx); +// +// JsonRpcResultOrError visit(EthSubscribeRequest request, ChannelHandlerContext ctx); +} diff --git a/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java b/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java new file mode 100644 index 00000000..2cfdb074 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java @@ -0,0 +1,30 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package io.xdag.rpc.modules.debug; + +import com.fasterxml.jackson.databind.JsonNode; + +import java.util.Map; + +public interface DebugModule { + + String wireProtocolQueueSize(); + + JsonNode traceTransaction(String transactionHash, Map traceOptions) throws Exception; +} diff --git a/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java b/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java new file mode 100644 index 00000000..5e3cbce2 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java @@ -0,0 +1,81 @@ +///* +// * This file is part of RskJ +// * Copyright (C) 2018 RSK Labs Ltd. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU Lesser General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU Lesser General Public License for more details. +// * +// * You should have received a copy of the GNU Lesser General Public License +// * along with this program. If not, see . +// */ +// +//package io.xdag.rpc.modules.debug; +// +//import com.fasterxml.jackson.databind.JsonNode; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.util.Map; +// +// +//public class DebugModuleImpl implements DebugModule { +// private static final Logger logger = LoggerFactory.getLogger("web3"); +// +// private final BlockStore blockStore; +// private final ReceiptStore receiptStore; +// +// private final MessageHandler messageHandler; +// private final BlockExecutor blockExecutor; +// +// public DebugModuleImpl( +// BlockStore blockStore, +// ReceiptStore receiptStore, +// MessageHandler messageHandler, +// BlockExecutor blockExecutor) { +// this.blockStore = blockStore; +// this.receiptStore = receiptStore; +// this.messageHandler = messageHandler; +// this.blockExecutor = blockExecutor; +// } +// +// @Override +// public String wireProtocolQueueSize() { +// long n = messageHandler.getMessageQueueSize(); +// return TypeConverter.toQuantityJsonHex(n); +// } +// +// @Override +// public JsonNode traceTransaction(String transactionHash, Map traceOptions) throws Exception { +// logger.trace("debug_traceTransaction({}, {})", transactionHash, traceOptions); +// +// if (traceOptions != null && !traceOptions.isEmpty()) { +// // TODO: implement the logic that takes into account trace options. +// logger.warn("Received {} trace options. For now trace options are being ignored", traceOptions); +// } +// +// byte[] hash = stringHexToByteArray(transactionHash); +// TransactionInfo txInfo = receiptStore.getInMainChain(hash, blockStore); +// +// if (txInfo == null) { +// logger.trace("No transaction info for {}", transactionHash); +// return null; +// } +// +// Block block = blockStore.getBlockByHash(txInfo.getBlockHash()); +// Block parent = blockStore.getBlockByHash(block.getParentHash().getBytes()); +// Transaction tx = block.getTransactionsList().get(txInfo.getIndex()); +// txInfo.setTransaction(tx); +// +// ProgramTraceProcessor programTraceProcessor = new ProgramTraceProcessor(); +// blockExecutor.traceBlock(programTraceProcessor, 0, block, parent.getHeader(), false, false); +// +// return programTraceProcessor.getProgramTraceAsJsonNode(tx.getHash()); +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParams.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParams.java new file mode 100644 index 00000000..4f149481 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParams.java @@ -0,0 +1,12 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonTypeInfo; +//import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +//import io.netty.channel.Channel; +// +//@JsonDeserialize(using = EthSubscribeParamsDeserializer.class) +//@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +//public interface EthSubscribeParams { +// SubscriptionId accept(EthSubscribeParamsVisitor visitor, Channel channel); +//} +// diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsDeserializer.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsDeserializer.java new file mode 100644 index 00000000..5cae0e35 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsDeserializer.java @@ -0,0 +1,60 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.core.JsonParser; +//import com.fasterxml.jackson.core.JsonToken; +//import com.fasterxml.jackson.databind.DeserializationContext; +//import com.fasterxml.jackson.databind.JsonDeserializer; +// +//import java.io.IOException; +//import java.util.HashMap; +// +//public class EthSubscribeParamsDeserializer extends JsonDeserializer { +// +// private final HashMap> subscriptionTypes; +// +// public EthSubscribeParamsDeserializer() { +// this.subscriptionTypes = new HashMap<>(); +// this.subscriptionTypes.put("newHeads", EthSubscribeNewHeadsParams.class); +// this.subscriptionTypes.put("logs", EthSubscribeLogsParams.class); +// } +// +// @Override +// public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { +// if (!p.isExpectedStartArrayToken()) { +// return ctxt.handleUnexpectedToken( +// EthSubscribeParams.class, +// p.currentToken(), +// p, +// "eth_subscribe parameters are expected to be arrays" +// ); +// } +// p.nextToken(); // skip '[' +// String subscriptionType = p.getText(); +// Class subscriptionTypeClass = subscriptionTypes.get(subscriptionType); +// p.nextToken(); +// EthSubscribeParams params; +// if (p.isExpectedStartObjectToken()) { +// params = p.readValueAs(subscriptionTypeClass); +// p.nextToken(); +// } else { +// try { +// params = subscriptionTypeClass.newInstance(); +// } catch (InstantiationException | IllegalAccessException e) { +// return ctxt.handleInstantiationProblem( +// subscriptionTypeClass, +// null, +// e +// ); +// } +// } +// if (p.currentToken() != JsonToken.END_ARRAY) { +// return ctxt.handleUnexpectedToken( +// EthSubscribeParams.class, +// p.currentToken(), +// p, +// "eth_subscribe can only have one object to configure subscription" +// ); +// } +// return params; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsVisitor.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsVisitor.java new file mode 100644 index 00000000..600e1e96 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeParamsVisitor.java @@ -0,0 +1,19 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import java.nio.channels.Channel; +// +//public interface EthSubscribeParamsVisitor { +// /** +// * @param params new heads subscription request parameters. +// * @param channel a Netty channel to subscribe notifications to. +// * @return a subscription id which should be used as an unsubscribe parameter. +// */ +// SubscriptionId visit(EthSubscribeNewHeadsParams params, Channel channel); +// +// /** +// * @param params logs subscription request parameters. +// * @param channel a Netty channel to subscribe notifications to. +// * @return a subscription id which should be used as an unsubscribe parameter. +// */ +// SubscriptionId visit(EthSubscribeLogsParams params, Channel channel); +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeRequest.java new file mode 100644 index 00000000..869bd7d4 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthSubscribeRequest.java @@ -0,0 +1,48 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonInclude; +//import com.fasterxml.jackson.annotation.JsonProperty; +//import io.netty.channel.ChannelHandlerContext; +//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +//import io.xdag.rpc.jsonrpc.JsonRpcVersion; +//import io.xdag.rpc.modules.XdagJsonRpcMethod; +//import io.xdag.rpc.modules.XdagJsonRpcRequest; +//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; +// +//import java.util.Objects; +// +//public class EthSubscribeRequest extends XdagJsonRpcRequest { +// +// private final EthSubscribeParams params; +// +// @JsonCreator +// public EthSubscribeRequest( +// @JsonProperty("jsonrpc") JsonRpcVersion version, +// @JsonProperty("method") XdagJsonRpcMethod method, +// @JsonProperty("id") Integer id, +// @JsonProperty("params") EthSubscribeParams params) { +// super(version, verifyMethod(method), Objects.requireNonNull(id)); +// this.params = Objects.requireNonNull(params); +// } +// +// @JsonInclude(JsonInclude.Include.NON_NULL) +// public EthSubscribeParams getParams() { +// return params; +// } +// +// @Override +// public JsonRpcResultOrError accept(XdagJsonRpcRequestVisitor visitor, ChannelHandlerContext ctx) { +// return visitor.visit(this, ctx); +// } +// +// private static XdagJsonRpcMethod verifyMethod(XdagJsonRpcMethod method) { +// if (method != XdagJsonRpcMethod.ETH_SUBSCRIBE) { +// throw new IllegalArgumentException( +// "Wrong method mapped to eth_subscribe. Check JSON mapping configuration in JsonRpcRequest." +// ); +// } +// +// return method; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeParams.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeParams.java new file mode 100644 index 00000000..be436596 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeParams.java @@ -0,0 +1,25 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonFormat; +//import com.fasterxml.jackson.annotation.JsonProperty; +//import com.fasterxml.jackson.annotation.JsonPropertyOrder; +// +//import java.util.Objects; +// +//@JsonFormat(shape=JsonFormat.Shape.ARRAY) +//@JsonPropertyOrder({"subscriptionId"}) +//public class EthUnsubscribeParams { +// +// private final SubscriptionId subscriptionId; +// +// @JsonCreator +// public EthUnsubscribeParams( +// @JsonProperty("subscriptionId") SubscriptionId subscriptionId) { +// this.subscriptionId = Objects.requireNonNull(subscriptionId); +// } +// +// public SubscriptionId getSubscriptionId() { +// return subscriptionId; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeRequest.java new file mode 100644 index 00000000..0d938696 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/EthUnsubscribeRequest.java @@ -0,0 +1,49 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonInclude; +//import com.fasterxml.jackson.annotation.JsonProperty; +//import io.netty.channel.ChannelHandlerContext; +//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +//import io.xdag.rpc.jsonrpc.JsonRpcVersion; +//import io.xdag.rpc.modules.XdagJsonRpcMethod; +//import io.xdag.rpc.modules.XdagJsonRpcRequest; +//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; +// +//import java.util.Objects; +// +//public class EthUnsubscribeRequest extends XdagJsonRpcRequest { +// +// private final EthUnsubscribeParams params; +// +// @JsonCreator +// public EthUnsubscribeRequest( +// @JsonProperty("jsonrpc") JsonRpcVersion version, +// @JsonProperty("method") XdagJsonRpcMethod method, +// @JsonProperty("id") int id, +// @JsonProperty("params") EthUnsubscribeParams params) { +// super(version, verifyMethod(method), id); +// this.params = params; +// } +// +// @JsonInclude(JsonInclude.Include.NON_NULL) +// public EthUnsubscribeParams getParams() { +// return params; +// } +// +// @Override +// public JsonRpcResultOrError accept(XdagJsonRpcRequestVisitor visitor, ChannelHandlerContext ctx) { +// return visitor.visit(this, ctx); +// } +// +// private static XdagJsonRpcMethod verifyMethod(XdagJsonRpcMethod method) { +// if (method != XdagJsonRpcMethod.ETH_UNSUBSCRIBE) { +// throw new IllegalArgumentException( +// "Wrong method mapped to eth_unsubscribe. Check JSON mapping configuration in JsonRpcRequest." +// ); +// } +// +// return method; +// } +// +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/subscribe/SubscriptionId.java b/src/main/java/io/xdag/rpc/modules/eth/subscribe/SubscriptionId.java new file mode 100644 index 00000000..c716c5c2 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/subscribe/SubscriptionId.java @@ -0,0 +1,52 @@ +//package io.xdag.rpc.modules.eth.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonValue; +//import io.xdag.rpc.jsonrpc.JsonRpcResult; +//import io.xdag.rpc.utils.TypeConverter; +// +//import java.security.SecureRandom; +//import java.util.Arrays; +// +//public class SubscriptionId extends JsonRpcResult { +// private final byte[] id; +// +// @JsonCreator +// public SubscriptionId(String hexId) { +// this.id = TypeConverter.stringHexToByteArray(hexId); +// } +// +// public SubscriptionId() { +// this.id = new byte[16]; +// new SecureRandom().nextBytes(id); +// } +// +// public byte[] getId() { +// return Arrays.copyOf(id, id.length); +// } +// +// @Override +// public int hashCode() { +// return Arrays.hashCode(id); +// } +// +// @Override +// public boolean equals(Object o) { +// if (o == this) { +// return true; +// } +// +// if (!(o instanceof SubscriptionId)) { +// return false; +// } +// +// SubscriptionId other = (SubscriptionId) o; +// return Arrays.equals(this.id, other.id); +// } +// +// @JsonValue +// @SuppressWarnings("unused") +// private String serialize() { +// return TypeConverter.toJsonHex(id); +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java new file mode 100644 index 00000000..8d0bc3a8 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java @@ -0,0 +1,122 @@ +//package io.xdag.rpc.modules.web3; +// +//import io.xdag.rpc.Web3; +// +//import java.math.BigInteger; +//import java.util.Map; +// +//public interface Web3EthModule { +// default String[] eth_accounts() { +// return getEthModule().accounts(); +// } +// +// default String eth_sign(String addr, String data) { +// return getEthModule().sign(addr, data); +// } +// +//// default String eth_call(Web3.CallArguments args, String bnOrId) { +//// return getEthModule().call(args, bnOrId); +//// } +// +//// default String eth_estimateGas(Web3.CallArguments args) { +//// return getEthModule().estimateGas(args); +//// } +// +// +// +//// default Map eth_bridgeState() throws Exception { +//// return getEthModule().bridgeState(); +//// } +// +//// default String eth_chainId() { +//// return getEthModule().chainId(); +//// } +// +// EthModule getEthModule(); +// +// String eth_protocolVersion(); +// +// Object eth_syncing(); +// +// String eth_coinbase(); +// +// boolean eth_mining(); +// +// BigInteger eth_hashrate(); +// +// String eth_gasPrice(); +// +// String eth_blockNumber(); +// +// String eth_getBalance(String address, String block) throws Exception; +// +// String eth_getBalance(String address) throws Exception; +// +// String eth_getStorageAt(String address, String storageIdx, String blockId) throws Exception; +// +// String eth_getTransactionCount(String address, String blockId) throws Exception ; +// +// String eth_getBlockTransactionCountByHash(String blockHash)throws Exception; +// +// String eth_getBlockTransactionCountByNumber(String bnOrId)throws Exception; +// +// String eth_getUncleCountByBlockHash(String blockHash)throws Exception; +// +// String eth_getUncleCountByBlockNumber(String bnOrId)throws Exception; +// +// default String eth_getCode(String address, String blockId) { +// return getEthModule().getCode(address, blockId); +// } +// +// default String eth_sendRawTransaction(String rawData) { +// return getEthModule().sendRawTransaction(rawData); +// } +// +// default String eth_sendTransaction(Web3.CallArguments args) { +// return getEthModule().sendTransaction(args); +// } +// +// BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransactionObjects) throws Exception; +// +// BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) throws Exception; +// +// TransactionResultDTO eth_getTransactionByHash(String transactionHash) throws Exception; +// +// TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) throws Exception; +// +// TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) throws Exception; +// +// TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) throws Exception; +// +// BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String uncleIdx) throws Exception; +// +// BlockResultDTO eth_getUncleByBlockNumberAndIndex(String blockId, String uncleIdx) throws Exception; +// +// String[] eth_getCompilers(); +// +// Map eth_compileLLL(String contract); +// +// Map eth_compileSerpent(String contract); +// +// Map eth_compileSolidity(String contract); +// +// String eth_newFilter(Web3.FilterRequest fr) throws Exception; +// +// String eth_newBlockFilter(); +// +// String eth_newPendingTransactionFilter(); +// +// boolean eth_uninstallFilter(String id); +// +// Object[] eth_getFilterChanges(String id); +// +// Object[] eth_getFilterLogs(String id); +// +// Object[] eth_getLogs(Web3.FilterRequest fr) throws Exception; +// +// BigInteger eth_netHashrate(); +// +// boolean eth_submitWork(String nonce, String header, String mince); +// +// boolean eth_submitHashrate(String hashrate, String id); +//} diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java new file mode 100644 index 00000000..0e4a0c9b --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java @@ -0,0 +1,51 @@ +package io.xdag.rpc.modules.web3; + +import io.xdag.rpc.Web3; +import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.modules.xdag.XdagModule; + + +public interface Web3XdagModule { + + default String[] xdag_accounts() { + return getXdagModule().accounts(); + } + + default String xdag_sign(String addr, String data) { + return getXdagModule().sign(addr, data); + } + + default String xdag_chainId() { + return getXdagModule().chainId(); + } + + + XdagModule getXdagModule(); + + String xdag_protocolVersion(); + + Object xdag_syncing(); + + String xdag_coinbase(); + + String xdag_blockNumber(); + + String xdag_getBalance(String address) throws Exception; + + default BlockResultDTO xdag_getTransactionByHash(String hash, Boolean full)throws Exception{ + return xdag_getBlockByHash(hash,full); + } + + BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws Exception; + + default String xdag_sendRawTransaction(String rawData) { + return getXdagModule().sendRawTransaction(rawData); + } + + default String xdag_sendTransaction(Web3.CallArguments args) { + return getXdagModule().sendTransaction(args); + } + + BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception; + +} diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java new file mode 100644 index 00000000..29a1f11f --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java @@ -0,0 +1,108 @@ +package io.xdag.rpc.modules.web3; + +import com.sun.jdi.LongValue; +import io.xdag.Kernel; +import io.xdag.core.Block; +import io.xdag.core.Blockchain; +import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.modules.xdag.XdagModule; +import io.xdag.utils.StringUtils; +import org.bouncycastle.util.encoders.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.Objects; + +import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; +import static io.xdag.utils.BasicUtils.address2Hash; +import static io.xdag.utils.BasicUtils.amount2xdag; + +public class Web3XdagModuleImpl implements Web3XdagModule{ + + private static final Logger logger = LoggerFactory.getLogger(Web3XdagModuleImpl.class); + + class SyncingResult { + public String currentBlock; + public String highestBlock; + } + + private final Blockchain blockchain; + private final XdagModule xdagModule; + private final Kernel kernel; + + public Web3XdagModuleImpl(Blockchain blockchain, XdagModule xdagModule, Kernel kernel) { + this.blockchain = blockchain; + this.xdagModule = xdagModule; + this.kernel = kernel; + } + + + @Override + public XdagModule getXdagModule() { + return xdagModule; + } + + @Override + public String xdag_protocolVersion() { + return null; + } + + @Override + public Object xdag_syncing() { + long currentBlock = this.blockchain.getXdagStats().nmain; + long highestBlock = this.blockchain.getXdagStats().totalnmain; + + if (highestBlock < currentBlock){ + return false; + } + + SyncingResult s = new SyncingResult(); + try { + s.currentBlock = toQuantityJsonHex(currentBlock); + s.highestBlock = toQuantityJsonHex(highestBlock); + + return s; + } finally { + logger.debug("xdag_syncing():current {}, highest {} ", s.currentBlock, s.highestBlock); + } + } + + @Override + public String xdag_coinbase() { + return Hex.toHexString(kernel.getPoolMiner().getAddressHash()); + } + + @Override + public String xdag_blockNumber() { + long b = blockchain.getXdagStats().nmain; + logger.debug("xdag_blockNumber(): {}", b); + + return toQuantityJsonHex(b); + } + + @Override + public String xdag_getBalance(String address) throws Exception { + byte[] hash; + if (org.apache.commons.lang3.StringUtils.length(address) == 32) { + hash = address2Hash(address); + } else { + hash = StringUtils.getHash(address); + } + byte[] key = new byte[32]; + System.arraycopy(Objects.requireNonNull(hash), 8, key, 8, 24); + Block block = kernel.getBlockStore().getBlockInfoByHash(key); + double balance = amount2xdag(block.getInfo().getAmount()); + return toQuantityJsonHex(balance); + } + + @Override + public BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws Exception { + return null; + } + + @Override + public BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception { + return null; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java new file mode 100644 index 00000000..fcb63739 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java @@ -0,0 +1,49 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.rpc.Web3; +import io.xdag.rpc.utils.TypeConverter; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Slf4j +public class XdagModule implements XdagModuleTransaction,XdagModuleWallet{ + + private static final Logger logger = LoggerFactory.getLogger(XdagModule.class); + + private final XdagModuleWallet xdagModuleWallet; + private final XdagModuleTransaction xdagModuleTransaction; + private final byte chainId; + + + public XdagModule(byte chainId, XdagModuleWallet xdagModuleWallet, XdagModuleTransaction xdagModuleTransaction) { + this.chainId = chainId; + this.xdagModuleWallet = xdagModuleWallet; + this.xdagModuleTransaction = xdagModuleTransaction; + } + + + public String chainId() { + return TypeConverter.toJsonHex(new byte[] { chainId }); + } + + @Override + public String sendTransaction(Web3.CallArguments args) { + return xdagModuleTransaction.sendTransaction(args); + } + + @Override + public String sendRawTransaction(String rawData) { + return xdagModuleTransaction.sendRawTransaction(rawData); + } + + @Override + public String[] accounts() { + return xdagModuleWallet.accounts(); + } + + @Override + public String sign(String addr, String data) { + return xdagModuleWallet.sign(addr,data); + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java new file mode 100644 index 00000000..e66dcb8d --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java @@ -0,0 +1,9 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.rpc.dto.BlockResultDTO; + +public interface XdagModuleChain { + String getCoinBase(); + BlockResultDTO getBlockByHash(String hash, boolean full); + BlockResultDTO getBlockByNumber(String bnOrId, boolean full); +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java new file mode 100644 index 00000000..fc0734bb --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java @@ -0,0 +1,24 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.modules.xdag.XdagModuleChain; + +public class XdagModuleChainBase implements XdagModuleChain { + + + + @Override + public String getCoinBase() { + return null; + } + + @Override + public BlockResultDTO getBlockByHash(String hash, boolean full) { + return null; + } + + @Override + public BlockResultDTO getBlockByNumber(String bnOrId, boolean full) { + return null; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java new file mode 100644 index 00000000..74134dd5 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java @@ -0,0 +1,9 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.rpc.Web3; + +public interface XdagModuleTransaction { + String sendTransaction(Web3.CallArguments args); + + String sendRawTransaction(String rawData); +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java new file mode 100644 index 00000000..62c3096e --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java @@ -0,0 +1,43 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.config.Constants; +import io.xdag.rpc.Web3; +import io.xdag.rpc.utils.TypeConverter; +import io.xdag.wallet.Wallet; +import org.bouncycastle.util.encoders.Hex; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; + +public class XdagModuleTransactionBase implements XdagModuleTransaction{ + protected static final Logger logger = LoggerFactory.getLogger(XdagModuleTransactionBase.class); + + + + @Override + public synchronized String sendTransaction(Web3.CallArguments args) { + + // 1. process args + byte[] from = Hex.decode(args.from); + byte[] to = Hex.decode(args.to); + BigInteger value = args.value != null ? TypeConverter.stringNumberAsBigInt(args.value) : BigInteger.ZERO; + + // 2. create a transaction + + // 3. try to add blockchain + + + return null; + } + + @Override + public String sendRawTransaction(String rawData) { + + // 1. build transaction + + // 2. try to add blockchain + + return null; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java new file mode 100644 index 00000000..9e3ffc5d --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java @@ -0,0 +1,24 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.rpc.Web3; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.xdag.rpc.exception.XdagJsonRpcRequestException.invalidParamError; + +public class XdagModuleTransactionDisabled extends XdagModuleTransactionBase{ + + private static final Logger logger = LoggerFactory.getLogger(XdagModuleTransactionDisabled.class); + + @Override + public String sendTransaction(Web3.CallArguments args) { + logger.debug("xdag_sendTransaction({}): {}", args, null); + throw invalidParamError("Local wallet is disabled in this node"); + } + + @Override + public String sendRawTransaction(String rawData) { + logger.debug("xdag_sendRawTransaction({}): {}", rawData, null); + throw invalidParamError("Local wallet is disabled in this node"); + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java new file mode 100644 index 00000000..10db63a1 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java @@ -0,0 +1,8 @@ +package io.xdag.rpc.modules.xdag; + +public interface XdagModuleWallet { + + String[] accounts(); + + String sign(String addr, String data); +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java new file mode 100644 index 00000000..51328a86 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java @@ -0,0 +1,28 @@ +package io.xdag.rpc.modules.xdag; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +import static io.xdag.rpc.exception.XdagJsonRpcRequestException.invalidParamError; + +public class XdagModuleWalletDisabled implements XdagModuleWallet{ + + private static final Logger logger = LoggerFactory.getLogger(XdagModuleWalletDisabled.class); + + + + @Override + public String[] accounts() { + String[] accounts = {}; + logger.debug("xdag_accounts(): {}", Arrays.toString(accounts)); + return accounts; + } + + @Override + public String sign(String addr, String data) { + logger.debug("eth_sign({}, {}): {}", addr, data, null); + throw invalidParamError("Local wallet is disabled in this node"); + } +} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java new file mode 100644 index 00000000..bef665d9 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java @@ -0,0 +1,15 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonTypeInfo; +//import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +//import io.netty.channel.Channel; +// +// +//@JsonDeserialize(using = EthSubscribeParamsDeserializer.class) +//@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) +//public interface XdagSubscribeParams { +// SubscriptionId accept(EthSubscribeParamsVisitor visitor, Channel channel); +//} +// +// +// diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java new file mode 100644 index 00000000..fc211d9f --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java @@ -0,0 +1,19 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//import io.netty.channel.Channel; +// +//public interface XdagSubscribeParamsVisitor { +// /** +// * @param params new heads subscription request parameters. +// * @param channel a Netty channel to subscribe notifications to. +// * @return a subscription id which should be used as an unsubscribe parameter. +// */ +// SubscriptionId visit(EthSubscribeNewHeadsParams params, Channel channel); +// +// /** +// * @param params logs subscription request parameters. +// * @param channel a Netty channel to subscribe notifications to. +// * @return a subscription id which should be used as an unsubscribe parameter. +// */ +// SubscriptionId visit(EthSubscribeLogsParams params, Channel channel); +//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java new file mode 100644 index 00000000..170ed7bb --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java @@ -0,0 +1,4 @@ +package io.xdag.rpc.modules.xdag.subscribe; + +public interface XdagSubscriptionNotificationDTO { +} diff --git a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java new file mode 100644 index 00000000..0b3f07f5 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java @@ -0,0 +1,128 @@ +package io.xdag.rpc.netty; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.*; +import io.xdag.rpc.cors.OriginValidator; +import io.xdag.rpc.utils.HttpUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.*; +import java.util.ArrayList; +import java.util.List; + + + +@ChannelHandler.Sharable +public class JsonRpcWeb3FilterHandler extends SimpleChannelInboundHandler { + private static final Logger logger = LoggerFactory.getLogger("jsonrpc"); + private final List rpcHost; + private final InetAddress rpcAddress; + private final List acceptedHosts; + + private OriginValidator originValidator; + + public JsonRpcWeb3FilterHandler(String corsDomains, InetAddress rpcAddress, List rpcHost) { + this.originValidator = new OriginValidator(corsDomains); + this.rpcHost = rpcHost; + this.rpcAddress = rpcAddress; + this.acceptedHosts = getAcceptedHosts(); + } + + private List getAcceptedHosts() { + List hosts = new ArrayList<>(); + if (isAcceptedAddress(rpcAddress)) { + hosts.add(rpcAddress.getHostName()); + hosts.add(rpcAddress.getHostAddress()); + } else { + for (String host : rpcHost) { + try { + InetAddress hostAddress = InetAddress.getByName(host); + if (!hostAddress.isAnyLocalAddress()) { + hosts.add(hostAddress.getHostAddress()); + hosts.add(hostAddress.getHostName()); + } else { + logger.warn("Wildcard address is not allowed on rpc host property {}", hostAddress); + } + } catch (UnknownHostException e) { + logger.warn("Invalid Host defined on rpc.host", e); + } + } + } + return hosts; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { + HttpResponse response; + HttpMethod httpMethod = request.getMethod(); + HttpHeaders headers = request.headers(); + + // when a request has multiple host fields declared it would be equivalent to a comma separated list + // the request will be inmediately rejected since it won't be parsed as a valid URI + // and won't work to match an item on rpc.host + String hostHeader = headers.get(HttpHeaders.Names.HOST); + String parsedHeader = parseHostHeader(hostHeader); + + if (!acceptedHosts.contains(parsedHeader)) { + logger.debug("Invalid header HOST {}", hostHeader); + response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST); + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + return; + } + + if (HttpMethod.POST.equals(httpMethod)) { + + String mimeType = HttpUtils.getMimeType(headers.get(HttpHeaders.Names.CONTENT_TYPE)); + String origin = headers.get(HttpHeaders.Names.ORIGIN); + String referer = headers.get(HttpHeaders.Names.REFERER); + + if (!"application/json".equals(mimeType) && !"application/json-rpc".equals(mimeType)) { + logger.debug("Unsupported content type"); + response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE); + } + else if (origin != null && !this.originValidator.isValidOrigin(origin)) { + logger.debug("Invalid origin"); + response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST); + } else if (referer != null && !this.originValidator.isValidReferer(referer)) { + logger.debug("Invalid referer"); + response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST); + } + else { + ctx.fireChannelRead(request); + return; + } + } else { + response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_IMPLEMENTED); + } + + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } + + private String parseHostHeader(String hostHeader) { + try { + // WORKAROUND: add any scheme to make the resulting URI valid. + URI uri = new URI("my://" + hostHeader); // may throw URISyntaxException + return uri.getHost(); + } catch (URISyntaxException e) { + return hostHeader; + } + } + + private boolean isAcceptedAddress(final InetAddress address) { + // Check if the address is a valid special local or loop back + if (address.isLoopbackAddress() ) { + return true; + } + // Check if the address is defined on any interface + try { + return !address.isAnyLocalAddress() && NetworkInterface.getByInetAddress(address) != null; + } catch (SocketException se) { + return false; + } + } + +} diff --git a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java new file mode 100644 index 00000000..fc1e2d68 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java @@ -0,0 +1,91 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package io.xdag.rpc.netty; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.googlecode.jsonrpc4j.*; +import io.netty.buffer.*; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.xdag.rpc.Web3; +import io.xdag.rpc.exception.XdagErrorResolver; +import io.xdag.rpc.filter.JsonRpcMethodFilter; +import io.xdag.rpc.modules.ModuleDescription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@ChannelHandler.Sharable +public class JsonRpcWeb3ServerHandler extends SimpleChannelInboundHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger("jsonrpc"); + + private final ObjectMapper mapper = new ObjectMapper(); + private final JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; + private final JsonRpcBasicServer jsonRpcServer; + + public JsonRpcWeb3ServerHandler(Web3 service, List filteredModules) { + this.jsonRpcServer = new JsonRpcBasicServer(service, service.getClass()); + jsonRpcServer.setRequestInterceptor(new JsonRpcMethodFilter(filteredModules)); + jsonRpcServer.setErrorResolver(new MultipleErrorResolver(new XdagErrorResolver(), AnnotationsErrorResolver.INSTANCE, DefaultErrorResolver.INSTANCE)); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBufHolder request) throws Exception { + ByteBuf responseContent = Unpooled.buffer(); + int responseCode; + try (ByteBufOutputStream os = new ByteBufOutputStream(responseContent); + ByteBufInputStream is = new ByteBufInputStream(request.content().retain())){ + + responseCode = jsonRpcServer.handleRequest(is, os); + } catch (Exception e) { + String unexpectedErrorMsg = "Unexpected error"; + LOGGER.error(unexpectedErrorMsg, e); + int errorCode = ErrorResolver.JsonError.CUSTOM_SERVER_ERROR_LOWER; + responseContent = buildErrorContent(errorCode, unexpectedErrorMsg); + responseCode = errorCode; + } + + ctx.fireChannelRead(new Web3Result( + responseContent, + responseCode + )); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + LOGGER.error("Unexpected exception", cause); + ctx.close(); + } + + private ByteBuf buildErrorContent(int errorCode, String errorMessage) throws JsonProcessingException { + Map errorProperties = new HashMap<>(); + errorProperties.put("code", jsonNodeFactory.numberNode(errorCode)); + errorProperties.put("message", jsonNodeFactory.textNode(errorMessage)); + JsonNode error = jsonNodeFactory.objectNode().set("error", jsonNodeFactory.objectNode().setAll(errorProperties)); + return Unpooled.wrappedBuffer(mapper.writeValueAsBytes(mapper.treeToValue(error, Object.class))); + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java b/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java new file mode 100644 index 00000000..b42b0862 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java @@ -0,0 +1,37 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package io.xdag.rpc.netty; + +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.*; + +public class Web3HttpMethodFilterHandler extends SimpleChannelInboundHandler { + @Override + protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) { + HttpMethod httpMethod = request.getMethod(); + if (HttpMethod.POST.equals(httpMethod)) { + // retain the request so it isn't released automatically by SimpleChannelInboundHandler + ctx.fireChannelRead(request.retain()); + } else { + HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_IMPLEMENTED); + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java b/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java new file mode 100644 index 00000000..bdb93600 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java @@ -0,0 +1,97 @@ +package io.xdag.rpc.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.codec.http.cors.CorsConfig; +import io.netty.handler.codec.http.cors.CorsHandler; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import io.xdag.rpc.cors.CorsConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; + +public class Web3HttpServer { + private static final Logger logger = LoggerFactory.getLogger(Web3HttpServer.class); + + private final InetAddress bindAddress; + private final int port; + private final EventLoopGroup bossGroup; + private final EventLoopGroup workerGroup; + private final int socketLinger; + private final boolean reuseAddress; + private final CorsConfiguration corsConfiguration; + private final JsonRpcWeb3FilterHandler jsonRpcWeb3FilterHandler; + private final JsonRpcWeb3ServerHandler jsonRpcWeb3ServerHandler; + + public Web3HttpServer(InetAddress bindAddress, + int port, + int socketLinger, + boolean reuseAddress, + CorsConfiguration corsConfiguration, + JsonRpcWeb3FilterHandler jsonRpcWeb3FilterHandler, + JsonRpcWeb3ServerHandler jsonRpcWeb3ServerHandler) { + this.bindAddress = bindAddress; + this.port = port; + this.socketLinger = socketLinger; + this.reuseAddress = reuseAddress; + this.corsConfiguration = corsConfiguration; + this.jsonRpcWeb3FilterHandler = jsonRpcWeb3FilterHandler; + this.jsonRpcWeb3ServerHandler = jsonRpcWeb3ServerHandler; + this.bossGroup = new NioEventLoopGroup(); + this.workerGroup = new NioEventLoopGroup(); + } + + public void start() { + logger.info("RPC HTTP enabled"); + + ServerBootstrap b = new ServerBootstrap(); + b.option(ChannelOption.SO_LINGER, socketLinger); + b.option(ChannelOption.SO_REUSEADDR, reuseAddress); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .handler(new LoggingHandler(LogLevel.INFO)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline p = ch.pipeline(); + p.addLast(new HttpRequestDecoder()); + p.addLast(new HttpResponseEncoder()); + p.addLast(new HttpObjectAggregator(1024 * 1024 * 5)); + p.addLast(new HttpContentCompressor()); + if (corsConfiguration.hasHeader()) { + p.addLast(new CorsHandler( + CorsConfig + .withOrigin(corsConfiguration.getHeader()) + .allowedRequestHeaders(HttpHeaders.Names.CONTENT_TYPE) + .allowedRequestMethods(HttpMethod.POST) + .build()) + ); + } + p.addLast(jsonRpcWeb3FilterHandler); + p.addLast(new Web3HttpMethodFilterHandler()); + p.addLast(jsonRpcWeb3ServerHandler); + p.addLast(new Web3ResultHttpResponseHandler()); + } + }); + try { + b.bind(bindAddress, port).sync(); + } catch (InterruptedException e) { + logger.error("The RPC HTTP server couldn't be started", e); + Thread.currentThread().interrupt(); + } + } + + public void stop() { + bossGroup.shutdownGracefully(); + workerGroup.shutdownGracefully(); + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3Result.java b/src/main/java/io/xdag/rpc/netty/Web3Result.java new file mode 100644 index 00000000..c658174d --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3Result.java @@ -0,0 +1,39 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package io.xdag.rpc.netty; + +import io.netty.buffer.ByteBuf; + +public class Web3Result { + + private final ByteBuf content; + private final int code; + + public Web3Result(ByteBuf content, int code) { + this.content = content; + this.code = code; + } + + public ByteBuf getContent() { + return content; + } + + public int getCode() { + return code; + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java b/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java new file mode 100644 index 00000000..565ced14 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java @@ -0,0 +1,50 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package io.xdag.rpc.netty; + +import com.googlecode.jsonrpc4j.DefaultHttpStatusCodeProvider; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.DefaultFullHttpResponse; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; + +import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; +import static io.netty.handler.codec.http.HttpHeaders.Values.APPLICATION_JSON; + +public class Web3ResultHttpResponseHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Web3Result msg) { + DefaultFullHttpResponse response = new DefaultFullHttpResponse( + HttpVersion.HTTP_1_1, + HttpResponseStatus.valueOf(DefaultHttpStatusCodeProvider.INSTANCE.getHttpStatusCode(msg.getCode())), + msg.getContent() + ); + + response.headers().add(CONTENT_TYPE, APPLICATION_JSON); + + ctx.write(response).addListener(ChannelFutureListener.CLOSE); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java b/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java new file mode 100644 index 00000000..75a5943d --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java @@ -0,0 +1,35 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package io.xdag.rpc.netty; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; + +public class Web3ResultWebSocketResponseHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Web3Result msg) { + ctx.write(new TextWebSocketFrame(msg.getContent())); + } + + @Override + public void channelReadComplete(ChannelHandlerContext ctx) { + ctx.flush(); + } +} diff --git a/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java new file mode 100644 index 00000000..edd36d28 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java @@ -0,0 +1,97 @@ +///* +// * This file is part of RskJ +// * Copyright (C) 2018 RSK Labs Ltd. +// * +// * This program is free software: you can redistribute it and/or modify +// * it under the terms of the GNU Lesser General Public License as published by +// * the Free Software Foundation, either version 3 of the License, or +// * (at your option) any later version. +// * +// * This program is distributed in the hope that it will be useful, +// * but WITHOUT ANY WARRANTY; without even the implied warranty of +// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// * GNU Lesser General Public License for more details. +// * +// * You should have received a copy of the GNU Lesser General Public License +// * along with this program. If not, see . +// */ +//package io.xdag.rpc.netty; +// +//import io.netty.bootstrap.ServerBootstrap; +//import io.netty.channel.ChannelFuture; +//import io.netty.channel.ChannelInitializer; +//import io.netty.channel.ChannelPipeline; +//import io.netty.channel.EventLoopGroup; +//import io.netty.channel.nio.NioEventLoopGroup; +//import io.netty.channel.socket.SocketChannel; +//import io.netty.channel.socket.nio.NioServerSocketChannel; +//import io.netty.handler.codec.http.HttpObjectAggregator; +//import io.netty.handler.codec.http.HttpServerCodec; +//import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import javax.annotation.Nullable; +//import java.net.InetAddress; +// +//public class Web3WebSocketServer { +// private static final Logger logger = LoggerFactory.getLogger(Web3WebSocketServer.class); +// +// private final InetAddress host; +// private final int port; +// private final XdagJsonRpcHandler jsonRpcHandler; +// private final JsonRpcWeb3ServerHandler web3ServerHandler; +// private final EventLoopGroup bossGroup; +// private final EventLoopGroup workerGroup; +// private @Nullable ChannelFuture webSocketChannel; +// +// public Web3WebSocketServer( +// InetAddress host, +// int port, +// XdagJsonRpcHandler jsonRpcHandler, +// JsonRpcWeb3ServerHandler web3ServerHandler) { +// this.host = host; +// this.port = port; +// this.jsonRpcHandler = jsonRpcHandler; +// this.web3ServerHandler = web3ServerHandler; +// this.bossGroup = new NioEventLoopGroup(); +// this.workerGroup = new NioEventLoopGroup(); +// } +// +// public void start() { +// logger.info("RPC WebSocket enabled"); +// ServerBootstrap b = new ServerBootstrap(); +// b.group(bossGroup, workerGroup) +// .channel(NioServerSocketChannel.class) +// .childHandler(new ChannelInitializer() { +// @Override +// protected void initChannel(SocketChannel ch) throws Exception { +// ChannelPipeline p = ch.pipeline(); +// p.addLast(new HttpServerCodec()); +// p.addLast(new HttpObjectAggregator(1024 * 1024 * 5)); +// p.addLast(new WebSocketServerProtocolHandler("/websocket")); +// p.addLast(jsonRpcHandler); +// p.addLast(web3ServerHandler); +// p.addLast(new Web3ResultWebSocketResponseHandler()); +// } +// }); +// webSocketChannel = b.bind(host, port); +// try { +// webSocketChannel.sync(); +// } catch (InterruptedException e) { +// logger.error("The RPC WebSocket server couldn't be started", e); +// Thread.currentThread().interrupt(); +// } +// } +// +// public void stop() { +// try { +// webSocketChannel.channel().close().sync(); +// } catch (InterruptedException e) { +// logger.error("Couldn't stop the RPC WebSocket server", e); +// Thread.currentThread().interrupt(); +// } +// this.bossGroup.shutdownGracefully(); +// this.workerGroup.shutdownGracefully(); +// } +//} diff --git a/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java new file mode 100644 index 00000000..f077d8a9 --- /dev/null +++ b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java @@ -0,0 +1,74 @@ +//package io.xdag.rpc.netty; +// +//import io.netty.buffer.ByteBufHolder; +//import io.netty.buffer.ByteBufInputStream; +//import io.netty.channel.ChannelHandlerContext; +//import io.netty.channel.SimpleChannelInboundHandler; +//import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +//import io.xdag.rpc.jsonrpc.JsonRpcBooleanResult; +//import io.xdag.rpc.jsonrpc.JsonRpcIdentifiableMessage; +//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +//import io.xdag.rpc.modules.XdagJsonRpcRequest; +//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; +//import io.xdag.rpc.modules.eth.subscribe.EthSubscribeRequest; +//import io.xdag.rpc.modules.eth.subscribe.EthUnsubscribeRequest; +//import io.xdag.rpc.serialize.JsonRpcSerializer; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import java.io.IOException; +// +//public class XdagJsonRpcHandler extends SimpleChannelInboundHandler +// implements XdagJsonRpcRequestVisitor { +// private static final Logger LOGGER = LoggerFactory.getLogger(XdagJsonRpcHandler.class); +// +//// private final EthSubscriptionNotificationEmitter emitter; +// private final JsonRpcSerializer serializer; +// +// public XdagJsonRpcHandler(JsonRpcSerializer serializer) { +// this.serializer = serializer; +// } +//// public XdagJsonRpcHandler(EthSubscriptionNotificationEmitter emitter, JsonRpcSerializer serializer) { +//// this.emitter = emitter; +//// this.serializer = serializer; +//// } +// +// @Override +// protected void channelRead0(ChannelHandlerContext ctx, ByteBufHolder msg) { +// try { +// XdagJsonRpcRequest request = serializer.deserializeRequest( +// new ByteBufInputStream(msg.copy().content()) +// ); +// +// // TODO(mc) we should support the ModuleDescription method filters +// JsonRpcResultOrError resultOrError = request.accept(this, ctx); +// JsonRpcIdentifiableMessage response = resultOrError.responseFor(request.getId()); +// ctx.writeAndFlush(new TextWebSocketFrame(serializer.serializeMessage(response))); +// return; +// } catch (IOException e) { +// LOGGER.trace("Not a known or valid JsonRpcRequest", e); +// } +// +// // delegate to the next handler if the message can't be matched to a known JSON-RPC request +// ctx.fireChannelRead(msg.retain()); +// } +// +// @Override +// public void channelInactive(ChannelHandlerContext ctx) throws Exception { +//// emitter.unsubscribe(ctx.channel()); +// super.channelInactive(ctx); +// } +// +// @Override +// public JsonRpcResultOrError visit(EthUnsubscribeRequest request, ChannelHandlerContext ctx) { +//// boolean unsubscribed = emitter.unsubscribe(request.getParams().getSubscriptionId()); +//// return new JsonRpcBooleanResult(unsubscribed); +// return null; +// } +// +// @Override +// public JsonRpcResultOrError visit(EthSubscribeRequest request, ChannelHandlerContext ctx) { +//// return request.getParams().accept(emitter, ctx.channel()); +// return null; +// } +//} diff --git a/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java b/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java new file mode 100644 index 00000000..5a352929 --- /dev/null +++ b/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java @@ -0,0 +1,25 @@ +package io.xdag.rpc.serialize; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.xdag.rpc.jsonrpc.JsonRpcMessage; +import io.xdag.rpc.modules.XdagJsonRpcRequest; + +import java.io.IOException; +import java.io.InputStream; + +public class JacksonBasedRpcSerializer implements JsonRpcSerializer { + //From https://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/ObjectMapper.html + // ObjectMapper is thread-safe as long as the config methods are not called after the serialiation begins. + private final ObjectMapper mapper = new ObjectMapper(); + + @Override + public String serializeMessage(JsonRpcMessage message) throws JsonProcessingException { + return mapper.writeValueAsString(message); + } + + @Override + public XdagJsonRpcRequest deserializeRequest(InputStream source) throws IOException { + return mapper.readValue(source, XdagJsonRpcRequest.class); + } +} diff --git a/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java b/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java new file mode 100644 index 00000000..322d902b --- /dev/null +++ b/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java @@ -0,0 +1,23 @@ +package io.xdag.rpc.serialize; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.xdag.rpc.jsonrpc.JsonRpcMessage; +import io.xdag.rpc.modules.XdagJsonRpcRequest; + +import java.io.IOException; +import java.io.InputStream; + +public interface JsonRpcSerializer { + /** + * @return a JsonRpcMessage serialized into a JSON string + * @throws JsonProcessingException when serialization fails + */ + String serializeMessage(JsonRpcMessage message) throws JsonProcessingException; + + /** + * @return an RskJsonRpcRequest deserialized from a JSON string in the source stream + * @throws IOException when deserialization fails + */ + XdagJsonRpcRequest deserializeRequest(InputStream source) throws IOException; +} + diff --git a/src/main/java/io/xdag/rpc/utils/HttpUtils.java b/src/main/java/io/xdag/rpc/utils/HttpUtils.java new file mode 100644 index 00000000..ba424275 --- /dev/null +++ b/src/main/java/io/xdag/rpc/utils/HttpUtils.java @@ -0,0 +1,24 @@ +package io.xdag.rpc.utils; + +public class HttpUtils { + /** This function is strongly based on the function from netty 4.1, since + * we have an older version from it and do not need the overhead of checking + * the rest of the implementation for security reasons. + * + * @param contentTypeValue the value obtained from the header Content-Type + * @return only the mime type, ignoring charset or other values after ; + */ + public static String getMimeType(String contentTypeValue) { + if (contentTypeValue == null) { + return null; + } + + int indexOfSemicolon = contentTypeValue.indexOf(';'); + if (indexOfSemicolon != -1) { + return contentTypeValue.substring(0, indexOfSemicolon); + } else { + return contentTypeValue.length() > 0 ? contentTypeValue : null; + } + + } +} diff --git a/src/main/java/io/xdag/rpc/utils/TypeConverter.java b/src/main/java/io/xdag/rpc/utils/TypeConverter.java new file mode 100644 index 00000000..ab4b21ec --- /dev/null +++ b/src/main/java/io/xdag/rpc/utils/TypeConverter.java @@ -0,0 +1,132 @@ +package io.xdag.rpc.utils; + +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +public class TypeConverter { + private static final Pattern LEADING_ZEROS_PATTERN = Pattern.compile("0x(0)+"); + + private TypeConverter() { + throw new IllegalAccessError("Utility class"); + } + + public static BigInteger stringNumberAsBigInt(String input) { + if (input.startsWith("0x")) { + return TypeConverter.stringHexToBigInteger(input); + } else { + return TypeConverter.stringDecimalToBigInteger(input); + } + } + + public static BigInteger stringHexToBigInteger(String input) { + if(!input.startsWith("0x")) { + throw new NumberFormatException("Invalid hex number, expected 0x prefix"); + } + String hexa = input.substring(2); + return new BigInteger(hexa, 16); + } + + private static BigInteger stringDecimalToBigInteger(String input) { + return new BigInteger(input); + } + + public static byte[] stringHexToByteArray(String x) { + String result = x; + if (x.startsWith("0x")) { + result = x.substring(2); + } + if (result.length() % 2 != 0) { + result = "0" + result; + } + return Hex.decode(result); + } + + public static byte[] stringToByteArray(String input) { + return input.getBytes(StandardCharsets.UTF_8); + } + + public static String toJsonHex(byte[] x) { + String result = toUnformattedJsonHex(x); + + if ("0x".equals(result)) { + return "0x00"; + } + + return result; + } + +// public static String toJsonHex(Coin x) { +// return x != null ? x.asBigInteger().toString() : "" ; +// } + + public static String toJsonHex(String x) { + return "0x"+x; + } + + /** + * @return A Hex representation of n WITHOUT leading zeroes + */ + public static String toQuantityJsonHex(long n) { + return "0x" + Long.toHexString(n); + } + + public static String toQuantityJsonHex(double n) { + return "" + n; + } + + /** + * @return A Hex representation of n WITHOUT leading zeroes + */ + public static String toQuantityJsonHex(BigInteger n) { + return "0x"+ n.toString(16); + } + + /** + * Converts a byte array to a string according to ethereum json-rpc specifications, null and empty + * convert to 0x. + * + * @param x An unformatted byte array + * @return A hex representation of the input with two hex digits per byte + */ + public static String toUnformattedJsonHex(byte[] x) { + return "0x" + (x == null ? "" : Hex.toHexString(x)); + } + + /** + * Converts a byte array representing a quantity according to ethereum json-rpc specifications. + * + *

+ * 0x000AEF -> 0x2AEF + *

+ * 0x00 -> 0x0 + * @param x A hex string with or without leading zeroes ("0x00AEF"). If null, it is considered as zero. + * @return A hex string without leading zeroes ("0xAEF") + */ + public static String toQuantityJsonHex(byte[] x) { + String withoutLeading = LEADING_ZEROS_PATTERN.matcher(toJsonHex(x)).replaceFirst("0x"); + if ("0x".equals(withoutLeading)) { + return "0x0"; + } + + return withoutLeading; + } + + /** + * Converts "0x876AF" to "876AF" + */ + public static String removeZeroX(String str) { + return str.substring(2); + } + + public static long JSonHexToLong(String x) { + if (!x.startsWith("0x")) { + throw new NumberFormatException("Incorrect hex syntax"); + } + x = x.substring(2); + return Long.parseLong(x, 16); + } +} + diff --git a/src/main/java/io/xdag/utils/BasicAuth.java b/src/main/java/io/xdag/utils/BasicAuth.java new file mode 100644 index 00000000..80452c39 --- /dev/null +++ b/src/main/java/io/xdag/utils/BasicAuth.java @@ -0,0 +1,48 @@ +package io.xdag.utils; + +import cn.hutool.core.lang.Pair; + +import java.util.Base64; + +/** + * Basic authentication helper. + * + */ +public class BasicAuth { + + /** + * Parses the username and password from the AUTHORIZATION header. + * + * @param auth + * @return a pair of username and password if success, otherwise null + */ + public static Pair parseAuth(String auth) { + try { + if (auth != null && auth.startsWith("Basic ")) { + String str = Bytes.toString(Base64.getDecoder().decode(auth.substring(6))); + int idx = str.indexOf(':'); + if (idx != -1) { + return Pair.of(str.substring(0, idx), str.substring(idx + 1)); + } + } + } catch (IllegalArgumentException e) { + // invalid base64 string + } + + return null; + } + + /** + * Generates the AUTHORIZATION header. + * + * @param username + * @param password + * @return + */ + public static String generateAuth(String username, String password) { + return "Basic " + Base64.getEncoder().encodeToString(Bytes.of(username + ":" + password)); + } + + private BasicAuth() { + } +} diff --git a/src/main/java/io/xdag/utils/BasicUtils.java b/src/main/java/io/xdag/utils/BasicUtils.java index 24a25d0c..0526e488 100644 --- a/src/main/java/io/xdag/utils/BasicUtils.java +++ b/src/main/java/io/xdag/utils/BasicUtils.java @@ -31,6 +31,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.text.NumberFormat; +import java.util.regex.Pattern; import java.util.zip.CRC32; public class BasicUtils { @@ -186,4 +187,21 @@ public static BigDecimal xdag_hashrate(BigInteger[] diffs) { public static double xdag_log_difficulty2hashrate(double logDiff) { return Math.exp(logDiff) * Math.pow(2, -58) * (0.65); } + + /** + * @param number should be in form '0x34fabd34....' + * @return String + */ + public static BigInteger unifiedNumericToBigInteger(String number) { + + boolean match = Pattern.matches("0[xX][0-9a-fA-F]+", number); + if (!match) { + return (new BigInteger(number)); + } else{ + number = number.substring(2); + number = number.length() % 2 != 0 ? "0".concat(number) : number; + byte[] numberBytes = Hex.decode(number); + return (new BigInteger(1, numberBytes)); + } + } } diff --git a/src/main/java/io/xdag/utils/Bytes.java b/src/main/java/io/xdag/utils/Bytes.java new file mode 100644 index 00000000..23bd796d --- /dev/null +++ b/src/main/java/io/xdag/utils/Bytes.java @@ -0,0 +1,271 @@ +/** + * Copyright (c) 2017-2020 The Semux Developers + * + * Distributed under the MIT software license, see the accompanying file + * LICENSE or https://opensource.org/licenses/mit-license.php + */ +package io.xdag.utils; + +import java.io.UnsupportedEncodingException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.List; + +public class Bytes { + + private static final SecureRandom secureRandom = new SecureRandom(); + + /** + * Default charset. + */ + public static final String CHARSET = "UTF-8"; + + /** + * Empty byte array. + */ + public static final byte[] EMPTY_BYTES = new byte[0]; + + /** + * Empty address. + */ + public static final byte[] EMPTY_ADDRESS = new byte[20]; + + /** + * Empty 256-bit hash. + *

+ * Note: this is not the hash of empty byte array. + */ + public static final byte[] EMPTY_HASH = new byte[32]; + + private Bytes() { + } + + /** + * Generate a random byte array of required length. + * + * @param n + * @return + */ + public static byte[] random(int n) { + byte[] bytes = new byte[n]; + secureRandom.nextBytes(bytes); + + return bytes; + } + + /** + * Merge two byte arrays into one. + * + * @param b1 + * @param b2 + * @return + */ + public static byte[] merge(byte[] b1, byte[] b2) { + byte[] res = new byte[b1.length + b2.length]; + System.arraycopy(b1, 0, res, 0, b1.length); + System.arraycopy(b2, 0, res, b1.length, b2.length); + + return res; + } + + /** + * Merge byte array and byte + * + * @param b1 + * @param b2 + * @return + */ + public static byte[] merge(byte[] b1, byte b2) { + byte[] res = new byte[b1.length + 1]; + System.arraycopy(b1, 0, res, 0, b1.length); + res[b1.length] = b2; + + return res; + } + + /** + * Merge byte and byte array. + * + * @param b1 + * @param b2 + * @return + */ + public static byte[] merge(byte b1, byte[] b2) { + byte[] res = new byte[1 + b2.length]; + res[0] = b1; + System.arraycopy(b2, 0, res, 1, b2.length); + + return res; + } + + /** + * Merge byte arrays into one. + * + * @param bytes + * byte arrays + * @return + */ + public static byte[] merge(byte[]... bytes) { + return merge(Arrays.asList(bytes)); + } + + /** + * Merge byte arrays into one. + * + * @param bytes + * byte arrays + * @return + */ + public static byte[] merge(List bytes) { + int length = 0; + for (byte[] b : bytes) { + length += b.length; + } + + byte[] res = new byte[length]; + int i = 0; + for (byte[] b : bytes) { + System.arraycopy(b, 0, res, i, b.length); + i += b.length; + } + + return res; + } + + /** + * Convert string into an byte array. + * + * @param str + * @return + */ + public static byte[] of(String str) { + try { + return str.getBytes(CHARSET); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + /** + * Convert a byte into an byte array. + * + * @param b + * @return + */ + public static byte[] of(byte b) { + return new byte[] { b }; + } + + /** + * Convert a short integer into an byte array. + * + * @param s + * @return + */ + public static byte[] of(short s) { + byte[] bytes = new byte[2]; + bytes[0] = (byte) ((s >> 8) & 0xff); + bytes[1] = (byte) (s & 0xff); + return bytes; + } + + /** + * Convert an integer into an byte array. + * + * @param i + * @return + */ + public static byte[] of(int i) { + byte[] bytes = new byte[4]; + bytes[0] = (byte) ((i >> 24) & 0xff); + bytes[1] = (byte) ((i >> 16) & 0xff); + bytes[2] = (byte) ((i >> 8) & 0xff); + bytes[3] = (byte) (i & 0xff); + return bytes; + } + + /** + * Convert a long integer into an byte array. + * + * @param i + * @return + */ + public static byte[] of(long i) { + byte[] bytes = new byte[8]; + bytes[0] = (byte) ((i >> 56) & 0xff); + bytes[1] = (byte) ((i >> 48) & 0xff); + bytes[2] = (byte) ((i >> 40) & 0xff); + bytes[3] = (byte) ((i >> 32) & 0xff); + bytes[4] = (byte) ((i >> 24) & 0xff); + bytes[5] = (byte) ((i >> 16) & 0xff); + bytes[6] = (byte) ((i >> 8) & 0xff); + bytes[7] = (byte) (i & 0xff); + return bytes; + } + + /** + * Convert byte array into string. + * + * @param bytes + * @return + */ + public static String toString(byte[] bytes) { + try { + return new String(bytes, CHARSET); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + /** + * Covert byte array into a byte. + * + * @param bytes + * @return + */ + public static byte toByte(byte[] bytes) { + return bytes[0]; + } + + /** + * Covert byte array into a short integer. + * + * @param bytes + * @return + */ + public static short toShort(byte[] bytes) { + return (short) (((bytes[0] & 0xff) << 8) | (bytes[1] & 0xff)); + } + + /** + * Covert byte array into an integer. + * + * @param bytes + * @return + */ + public static int toInt(byte[] bytes) { + return ((bytes[0] & 0xff) << 24) + | ((bytes[1] & 0xff) << 16) + | ((bytes[2] & 0xff) << 8) + | (bytes[3] & 0xff); + } + + /** + * Covert byte array into a long integer. + * + * @param bytes + * @return + */ + public static long toLong(byte[] bytes) { + return ((bytes[0] & 0xffL) << 56) + | ((bytes[1] & 0xffL) << 48) + | ((bytes[2] & 0xffL) << 40) + | ((bytes[3] & 0xffL) << 32) + | ((bytes[4] & 0xffL) << 24) + | ((bytes[5] & 0xffL) << 16) + | ((bytes[6] & 0xffL) << 8) + | (bytes[7] & 0xff); + } + + +} diff --git a/src/main/java/io/xdag/utils/BytesUtils.java b/src/main/java/io/xdag/utils/BytesUtils.java index 5ede9dee..7856867b 100644 --- a/src/main/java/io/xdag/utils/BytesUtils.java +++ b/src/main/java/io/xdag/utils/BytesUtils.java @@ -33,6 +33,9 @@ public class BytesUtils { + public static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + private static final byte[] ZERO_BYTE_ARRAY = new byte[]{0}; + public static byte[] intToBytes(int value, boolean littleEndian) { ByteBuffer buffer = ByteBuffer.allocate(4); if (littleEndian) { @@ -305,4 +308,38 @@ public static double hexBytesToDouble(byte[] input, int offset, boolean littleEn public String byteToBinaryString(byte b) { return Integer.toBinaryString(b & 0xFF); } + + public static byte[] stripLeadingZeroes(byte[] data) { + return stripLeadingZeroes(data, ZERO_BYTE_ARRAY); + } + + public static byte[] stripLeadingZeroes(byte[] data, byte[] valueForZero) { + if (data == null) { + return null; + } + + final int firstNonZero = firstNonZeroByte(data); + switch (firstNonZero) { + case -1: + return valueForZero; + + case 0: + return data; + + default: + byte[] result = new byte[data.length - firstNonZero]; + System.arraycopy(data, firstNonZero, result, 0, data.length - firstNonZero); + + return result; + } + } + + public static int firstNonZeroByte(byte[] data) { + for (int i = 0; i < data.length; ++i) { + if (data[i] != 0) { + return i; + } + } + return -1; + } } diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml index a3418cf9..0ee4dd9e 100644 --- a/src/main/resources/log4j2.xml +++ b/src/main/resources/log4j2.xml @@ -68,7 +68,7 @@ - + diff --git a/src/test/java/io/xdag/BlockBuilder.java b/src/test/java/io/xdag/BlockBuilder.java index c70e7c10..5a3a2212 100644 --- a/src/test/java/io/xdag/BlockBuilder.java +++ b/src/test/java/io/xdag/BlockBuilder.java @@ -47,7 +47,7 @@ public static Block generateAddressBlock(Config config, ECKeyPair key, long xdag } public static Block generateExtraBlock(Config config, ECKeyPair key, long xdagTime, List

pendings) { - Block b = new Block(config, xdagTime, null, pendings, false, null, null, -1); + Block b = new Block(config, xdagTime, null, pendings, true, null, null, -1); b.signOut(key); byte[] random = Hash.sha256(Hex.decode("1234")); b.setNonce(random); @@ -55,7 +55,7 @@ public static Block generateExtraBlock(Config config, ECKeyPair key, long xdagTi } public static Block generateExtraBlockGivenRandom(Config config, ECKeyPair key, long xdagTime, List
pendings, String randomS) { - Block b = new Block(config, xdagTime, null, pendings, false, null, null, -1); + Block b = new Block(config, xdagTime, null, pendings, true, null, null, -1); b.signOut(key); byte[] random = Hash.sha256(Hex.decode(randomS)); b.setNonce(random); diff --git a/src/test/java/io/xdag/core/BlockchainTest.java b/src/test/java/io/xdag/core/BlockchainTest.java index 2a46073f..3da4dfba 100644 --- a/src/test/java/io/xdag/core/BlockchainTest.java +++ b/src/test/java/io/xdag/core/BlockchainTest.java @@ -257,6 +257,58 @@ public void testTransactionBlock() throws ParseException { assertEquals("1124.0", String.valueOf(amount2xdag(toBlock.getInfo().getAmount()))); // block reword 1024 - 100 = 924.0 assertEquals("924.0", String.valueOf(amount2xdag(fromBlock.getInfo().getAmount()))); + + + // test two key to use + // 4. make one transaction(100 XDAG) block(from No.1 mainblock to address block) + to = new Address(extraBlockList.get(0).getHashLow(), XDAG_FIELD_IN); + from = new Address(addressBlock.getHashLow(), XDAG_FIELD_OUT); + xdagTime = XdagTime.getEndOfEpoch(XdagTime.msToXdagtimestamp(generateTime)); + + + List refs = Lists.newArrayList(); + refs.add(new Address(from.getHashLow(), XdagField.FieldType.XDAG_FIELD_IN, xdag2amount(50.00))); // key1 + refs.add(new Address(to.getHashLow(), XDAG_FIELD_OUT, xdag2amount(50.00))); + List keys = new ArrayList<>(); + keys.add(addrKey); + Block b = new Block(config, xdagTime, refs, null, false, keys, null, -1); // orphan + b.signIn(addrKey); + b.signOut(poolKey); + + txBlock = b; + + // 4. local check + assertTrue(blockchain.canUseInput(txBlock)); + // 5. remote check + assertTrue(blockchain.canUseInput(new Block(txBlock.getXdagBlock()))); + + + result = blockchain.tryToConnect(txBlock); + // import transaction block, result may be IMPORTED_NOT_BEST or IMPORTED_BEST + assertTrue(result == IMPORTED_NOT_BEST || result == IMPORTED_BEST); + // there is 12 blocks and 10 mainblocks +// assertChainStatus(12, 10, 1,1, blockchain); + + pending.clear(); + pending.add(new Address(txBlock.getHashLow())); + ref = extraBlockList.get(extraBlockList.size()-1).getHashLow(); + // 4. confirm transaction block with 3 mainblocks + for(int i = 1; i <= 3; i++) { + generateTime += 64000L; + pending.add(new Address(ref, XDAG_FIELD_OUT)); + long time = XdagTime.msToXdagtimestamp(generateTime); + xdagTime = XdagTime.getEndOfEpoch(time); + Block extraBlock = generateExtraBlock(config, poolKey, xdagTime, pending); + blockchain.tryToConnect(extraBlock); + ref = extraBlock.getHashLow(); + extraBlockList.add(extraBlock); + pending.clear(); + } + + toBlock = blockchain.getBlockStore().getBlockInfoByHash(to.getHashLow()); + fromBlock = blockchain.getBlockStore().getBlockInfoByHash(from.getHashLow()); + assertEquals("974.0", String.valueOf(amount2xdag(toBlock.getInfo().getAmount()))); + assertEquals("1074.0", String.valueOf(amount2xdag(fromBlock.getInfo().getAmount()))); } @Test @@ -368,8 +420,8 @@ public void testOriginFork() throws ParseException { BigInteger privateKey = new BigInteger(privString, 16); - String firstDiff = "50372dcc7b"; - String secondDiff = "7fd767e345"; + String firstDiff = "aedbac91e1"; + String secondDiff = "d936e19b89"; ECKeyPair addrKey = ECKeyPair.create(privateKey); ECKeyPair poolKey = ECKeyPair.create(privateKey); diff --git a/src/test/java/io/xdag/core/RandomXSyncTest.java b/src/test/java/io/xdag/core/RandomXSyncTest.java index ff8049ad..81653d9e 100644 --- a/src/test/java/io/xdag/core/RandomXSyncTest.java +++ b/src/test/java/io/xdag/core/RandomXSyncTest.java @@ -76,7 +76,7 @@ public void init() { RandomXConstants.SEEDHASH_EPOCH_TESTNET_BLOCKS = 64; RandomXConstants.RANDOMX_TESTNET_FORK_HEIGHT = 128; RandomXConstants.SEEDHASH_EPOCH_TESTNET_LAG = 4; - forkHeight = 3; + forkHeight = 2; } From 0fb0f39986fd13a38e705f05340210efd471aca8 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Tue, 25 May 2021 10:28:26 +0800 Subject: [PATCH 02/11] add rpc modules config --- docs/README_zh.md | 72 +++++-- ...ation_RandomX_Algorithm_Environment_eng.md | 8 +- ...ration_RandomX_Algorithm_Environment_zh.md | 9 +- pom.xml | 10 + src/main/java/io/xdag/Kernel.java | 55 +++-- .../java/io/xdag/config/AbstractConfig.java | 58 +++--- .../java/io/xdag/config/TestnetConfig.java | 2 +- src/main/java/io/xdag/rpc/Web3.java | 4 +- src/main/java/io/xdag/rpc/Web3Impl.java | 151 ++++++++++++++ .../java/io/xdag/rpc/dto/BlockResultDTO.java | 7 + .../io/xdag/rpc/jsonrpc/JsonRpcMessage.java | 2 + .../xdag/rpc/modules/XdagJsonRpcRequest.java | 2 - .../modules/XdagJsonRpcRequestVisitor.java | 7 - .../xdag/rpc/modules/web3/Web3XdagModule.java | 2 + .../rpc/modules/web3/Web3XdagModuleImpl.java | 32 ++- .../xdag/subscribe/SubscriptionId.java | 52 +++++ .../xdag/subscribe/XDAGSubscribeRequest.java | 47 +++++ .../subscribe/XDAGUnsubscribeRequest.java | 4 + .../xdag/subscribe/XdagSubscribeParams.java | 4 +- .../XdagSubscribeParamsDeserializer.java | 60 ++++++ .../subscribe/XdagSubscribeParamsVisitor.java | 26 +-- .../XdagSubscriptionNotificationDTO.java | 8 +- .../xdag/rpc/netty/Web3WebSocketServer.java | 194 +++++++++--------- .../io/xdag/rpc/netty/XdagJsonRpcHandler.java | 120 ++++++----- src/main/java/io/xdag/utils/BasicUtils.java | 110 +++++----- src/main/resources/rpc_modules.conf | 96 +++++++++ src/main/resources/xdag-testnet.config | 58 ++++++ .../java/io/xdag/core/BlockchainTest.java | 23 ++- .../java/io/xdag/core/ExtraBlockTest.java | 7 +- .../java/io/xdag/core/RandomXSyncTest.java | 4 +- src/test/java/io/xdag/core/RewardTest.java | 6 +- .../jsonrpc/JsonRpcResultResponseTest.java | 24 +++ 32 files changed, 935 insertions(+), 329 deletions(-) create mode 100644 src/main/java/io/xdag/rpc/Web3Impl.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java create mode 100644 src/main/resources/rpc_modules.conf create mode 100644 src/test/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponseTest.java diff --git a/docs/README_zh.md b/docs/README_zh.md index f0d3f00b..e2a0f842 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -9,6 +9,7 @@ - [系统环境](#系统环境) - [安装与用法](#安装与用法) - [发展](#发展) + - [火星计划](#火星计划) - [代码规范](#代码规范) - [贡献](#贡献) - [赞助](#赞助) @@ -36,25 +37,58 @@ XDAGJ教程可以让您快速加入并体验XDAGJ的钱包及挖矿功能,私 XDAGJ已经具备了一个矿池基本的功能,后续的工作继续优化现有代码,提升系统的稳定性。及时吸纳优秀的区块链技术,不断为XDAG注入新鲜血液 -下一阶段的主要工作包括但不限于下述内容 - -- 优化XDAG共识流程以及同步协议 -- 使用Libp2p替换当前的dnet网络,在系统稳定性允许的前提下逐步提高去中心化程度 -- 开放API接口,提供黑盒测试 -- 提供各类符合Web3j规范的RPC接口 -- 为交易加入手续费,提高用户的参与度 -- 利用BIPxx等规范改进现有公私钥及地址产生方式,提供一种更为方便且通用的密钥存储方式 -- 添加快照功能,解决历史主块加载速度慢的问题 -- 优化地址块结构,避免粉尘攻击 - - -与此同时,我们也在积极的为XDAG更多的应用场景,包括但不限于以下内容 - -- 探索使用neo4j作为存储层的可能,提供一种可视化的DAG存储 -- 探索一种在XDAG中加入虚拟机,实现智能合约的方法,提高系统的可用性 -- 探索有效的跨链方案,打破XDAG的封闭生态 - - +### 火星计划 + +火星计划优先解决社区关注的技术问题,期间研究有重大突破可灵活加入开发计划,最新阶段性计划如下: + +#### 探索阶段:XDAGJ测试网上线(已上线,公测中) + +- [x] 部署XDAGJ测试网环境,开放公测 + +- [x] 接入RandomX算法 + +- [x] 接入libp2p协议 + +- [x] 测试网区块链浏览器 + +- [x] 测试币获取 + + +#### 登陆阶段:XDAGJ主网上线 + +- [ ] 完善测试案例:逐步完善现有功能的测试案例 + +- [ ] 完善日志功能:提供较为完整的日志功能,便于后期问题排查 + +- [ ] 优化同步协议:改进现有的同步协议,提高同步效率 + +- [ ] 实现快照功能:解决历史区块过多所造成的加载数据耗时较长问题 + +- [ ] 实现RPC功能:接入Web3j,实现接口的规范化 + +- [ ] 挖矿协议改进:引入较成熟的Stratum协议,方便矿机的接入与使用 + +- [ ] 轻量级钱包应用:接入MateMask,加入浏览器钱包 + +- [ ] 规范公私钥格式,遵循BIPXX规范,加入助记词方式生成公私钥对 + +#### 拓展阶段:XDAGJ & EVM 拓展 + +- [ ] 修改地址块结构,增加手续费 + +- [ ] 优化改善移动端钱包,提高用户体验 + +- [ ] 开放智能合约,实现支持Solidity的EVM,兼容以太坊智能合约 + +- [ ] 降低矿池门槛,逐步开放白名单从而实现完全中心化 + +#### 繁荣阶段:DAG & DeFi + +- [ ] 跨链:兼容多种区块链系统接入,实现XDAG与其它链世界的互通 + +- [ ] 加入预言机 + +- [ ] 加入分布式交易所 ## 代码规范 diff --git a/docs/Win10_Configuration_RandomX_Algorithm_Environment_eng.md b/docs/Win10_Configuration_RandomX_Algorithm_Environment_eng.md index 310a1b31..65e4a1df 100644 --- a/docs/Win10_Configuration_RandomX_Algorithm_Environment_eng.md +++ b/docs/Win10_Configuration_RandomX_Algorithm_Environment_eng.md @@ -22,7 +22,7 @@ pause - Modify the above file to xxx.bat file, then right-click to run as an administrator, and wait for the program to end -![Open the security group](./Open_the_security_group.png) +![Open the security group](img/Open_the_security_group.png) ### Open hugeoage @@ -30,12 +30,12 @@ pause - Find the `windows management tool`, and open it after going to the `local security policy` -![RandomX_first](./RandomX_first.png) +![RandomX_first](img/RandomX_first.png) - Click `Local Policies`->`User Rights Assignment`->`Lock Memory Pages` -![RandomX_two](./RandomX_two.png) +![RandomX_two](img/RandomX_two.png) - Add the computer user name for the locked memory page, restart the computer after confirmation -![RandomX_three](./RandomX_three.png) +![RandomX_three](img/RandomX_three.png) diff --git a/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md b/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md index 037e8810..56cd5619 100644 --- a/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md +++ b/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md @@ -22,7 +22,7 @@ pause - 修改上述文件为xxx.bat文件,然后右键用管理员身份运行,等待程序运行结束即可 -![Open the security group](./Open_the_security_group.png) +![Open the security group](img/Open_the_security_group.png) ## 开启hugeoage功能 @@ -30,14 +30,13 @@ pause - 找到`windows管理工具`,并在里面到`本地安全策略`后打开 -![RandomX_first](./RandomX_first.png) +![RandomX_first](img/RandomX_first.png) - 点击`本地策略`->`用户权限分配`->`锁定内存页` -![RandomX_two](./RandomX_two.png) +![RandomX_two](img/RandomX_two.png) - 为锁定内存页添加计算机用户名,确认之后重启电脑 -![RandomX_three](./RandomX_three.png) +![RandomX_three](img/RandomX_three.png) - \ No newline at end of file diff --git a/pom.xml b/pom.xml index e1f89792..3bae316f 100644 --- a/pom.xml +++ b/pom.xml @@ -581,6 +581,16 @@ + + + + com.typesafe + config + 1.4.1 + + + + diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 05570b2b..bfb7e1d1 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -60,8 +60,13 @@ import io.xdag.net.node.NodeManager; import io.xdag.randomx.RandomX; import io.xdag.rpc.Web3; +import io.xdag.rpc.Web3Impl; import io.xdag.rpc.cors.CorsConfiguration; +import io.xdag.rpc.modules.web3.Web3XdagModule; import io.xdag.rpc.modules.web3.Web3XdagModuleImpl; +import io.xdag.rpc.modules.xdag.XdagModule; +import io.xdag.rpc.modules.xdag.XdagModuleTransactionDisabled; +import io.xdag.rpc.modules.xdag.XdagModuleWalletDisabled; import io.xdag.rpc.netty.*; import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; import io.xdag.rpc.serialize.JsonRpcSerializer; @@ -126,7 +131,7 @@ public class Kernel { // rpc protected JsonRpcWeb3ServerHandler jsonRpcWeb3ServerHandler; protected Web3 web3; -// protected Web3WebSocketServer web3WebSocketServer; + protected Web3WebSocketServer web3WebSocketServer; protected Web3HttpServer web3HttpServer; protected JsonRpcWeb3FilterHandler jsonRpcWeb3FilterHandler; protected JacksonBasedRpcSerializer jacksonBasedRpcSerializer; @@ -295,6 +300,12 @@ public synchronized void testStart() throws Exception { xdagState = XdagState.WTST; } + // ==================================== + // rpc start + // ==================================== + getWeb3HttpServer().start(); + getWeb3WebSocketServer().start(); + // ==================================== // telnet server // ==================================== @@ -312,7 +323,8 @@ private Web3 getWeb3() { } private Web3 buildWeb3() { - return null; + Web3XdagModule web3XdagModule = new Web3XdagModuleImpl(this.getBlockchain(),new XdagModule((byte) 0x1,new XdagModuleWalletDisabled(),new XdagModuleTransactionDisabled()),this); + return new Web3Impl(web3XdagModule); } private JsonRpcWeb3ServerHandler getJsonRpcWeb3ServerHandler() { @@ -325,26 +337,26 @@ private JsonRpcWeb3ServerHandler getJsonRpcWeb3ServerHandler() { return jsonRpcWeb3ServerHandler; } -// -// private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException { -// if (web3WebSocketServer == null) { -// JsonRpcSerializer jsonRpcSerializer = getJsonRpcSerializer(); -// XdagJsonRpcHandler jsonRpcHandler = new XdagJsonRpcHandler(jsonRpcSerializer); -// web3WebSocketServer = new Web3WebSocketServer( -// InetAddress.getLocalHost(), -// 4444, -// jsonRpcHandler, -// getJsonRpcWeb3ServerHandler() -// ); -// } -// -// return web3WebSocketServer; -// } + + private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException { + if (web3WebSocketServer == null) { + JsonRpcSerializer jsonRpcSerializer = getJsonRpcSerializer(); + XdagJsonRpcHandler jsonRpcHandler = new XdagJsonRpcHandler(jsonRpcSerializer); + web3WebSocketServer = new Web3WebSocketServer( + InetAddress.getByName("127.0.0.1"), + 4444, + jsonRpcHandler, + getJsonRpcWeb3ServerHandler() + ); + } + + return web3WebSocketServer; + } private Web3HttpServer getWeb3HttpServer() throws UnknownHostException { if (web3HttpServer == null) { web3HttpServer = new Web3HttpServer( - InetAddress.getLocalHost(), + InetAddress.getByName("127.0.0.1"), 4445, 123, true, @@ -361,7 +373,7 @@ private JsonRpcWeb3FilterHandler getJsonRpcWeb3FilterHandler() throws UnknownHos if (jsonRpcWeb3FilterHandler == null) { jsonRpcWeb3FilterHandler = new JsonRpcWeb3FilterHandler( "*", - InetAddress.getLocalHost(), + InetAddress.getByName("127.0.0.1"), null ); } @@ -385,6 +397,11 @@ public synchronized void testStop() { isRunning.set(false); + // + if (web3HttpServer != null) { + web3HttpServer.stop(); + } + // 1. 工作层关闭 // stop consensus sync.stop(); diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index ca335da2..c4878acf 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -24,6 +24,8 @@ package io.xdag.config; import cn.hutool.setting.Setting; +import com.typesafe.config.ConfigFactory; +import com.typesafe.config.ConfigObject; import io.xdag.config.spec.*; import io.xdag.core.XdagField; import io.xdag.crypto.DnetKeys; @@ -340,34 +342,40 @@ public List getRpcModules() { List modules = new ArrayList<>(); - // TODO: get modules from config -// if (!configFromFiles.hasPath("rpc.modules")) { -// return modules; -// } -// -// List list = configFromFiles.getObjectList("rpc.modules"); -// -// for (ConfigObject configObject : list) { -// Config configElement = configObject.toConfig(); -// String name = configElement.getString("name"); -// String version = configElement.getString("version"); -// boolean enabled = configElement.getBoolean("enabled"); -// List enabledMethods = null; -// List disabledMethods = null; -// -// if (configElement.hasPath("methods.enabled")) { -// enabledMethods = configElement.getStringList("methods.enabled"); -// } -// -// if (configElement.hasPath("methods.disabled")) { -// disabledMethods = configElement.getStringList("methods.disabled"); -// } -// -// modules.add(new ModuleDescription(name, version, enabled, enabledMethods, disabledMethods)); -// } + com.typesafe.config.Config configFromFiles = ConfigFactory.load("rpc_modules"); + List list = configFromFiles.getObjectList("rpc.modules"); + + for (ConfigObject configObject : list) { + com.typesafe.config.Config configElement = configObject.toConfig(); + String name = configElement.getString("name"); + String version = configElement.getString("version"); + boolean enabled = configElement.getBoolean("enabled"); + List enabledMethods = null; + List disabledMethods = null; + + if (configElement.hasPath("methods.enabled")) { + enabledMethods = configElement.getStringList("methods.enabled"); + } + + if (configElement.hasPath("methods.disabled")) { + disabledMethods = configElement.getStringList("methods.disabled"); + } + + modules.add(new ModuleDescription(name, version, enabled, enabledMethods, disabledMethods)); + } this.moduleDescriptions = modules; + // TODO: get modules from config +// String name = "xdag"; +// String version = "1.0"; +// boolean enabled = true; +// List enabledMethods = null; +// List disabledMethods = null; +// +// modules.add(new ModuleDescription(name, version, enabled, enabledMethods, disabledMethods)); +// this.moduleDescriptions = modules; + return modules; } } diff --git a/src/main/java/io/xdag/config/TestnetConfig.java b/src/main/java/io/xdag/config/TestnetConfig.java index 4e9d5418..4dedf91f 100644 --- a/src/main/java/io/xdag/config/TestnetConfig.java +++ b/src/main/java/io/xdag/config/TestnetConfig.java @@ -33,7 +33,7 @@ public TestnetConfig() { this.whitelistUrl = "https://raw.githubusercontent.com/XDagger/xdag/master/client/netdb-white-testnet.txt"; // testnet wait 1 epoch - this.waitEpoch = 10; + this.waitEpoch = 1; this.xdagEra = 0x16900000000L; this.mainStartAmount = UnsignedLong.fromLongBits(1L << 42).longValue(); diff --git a/src/main/java/io/xdag/rpc/Web3.java b/src/main/java/io/xdag/rpc/Web3.java index a5b7e56e..78e91e37 100644 --- a/src/main/java/io/xdag/rpc/Web3.java +++ b/src/main/java/io/xdag/rpc/Web3.java @@ -1,9 +1,11 @@ package io.xdag.rpc; +import io.xdag.rpc.modules.web3.Web3XdagModule; + import java.util.Arrays; import java.util.Map; -public interface Web3 { +public interface Web3 extends Web3XdagModule { class CallArguments { public String from; public String to; diff --git a/src/main/java/io/xdag/rpc/Web3Impl.java b/src/main/java/io/xdag/rpc/Web3Impl.java new file mode 100644 index 00000000..471da0b3 --- /dev/null +++ b/src/main/java/io/xdag/rpc/Web3Impl.java @@ -0,0 +1,151 @@ +package io.xdag.rpc; + +import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.modules.web3.Web3XdagModule; +import io.xdag.rpc.modules.xdag.XdagModule; + +import java.util.Map; + +public class Web3Impl implements Web3{ + + Web3XdagModule web3XdagModule; + + public Web3Impl(Web3XdagModule web3XdagModule) { + this.web3XdagModule = web3XdagModule; + } + + @Override + public String web3_clientVersion() { + return null; + } + + @Override + public String web3_sha3(String data) throws Exception { + return null; + } + + @Override + public String net_version() { + return null; + } + + @Override + public String net_peerCount() { + return null; + } + + @Override + public boolean net_listening() { + return false; + } + + @Override + public String[] net_peerList() { + return new String[0]; + } + + @Override + public Map rpc_modules() { + return null; + } + + @Override + public void db_putString() { + + } + + @Override + public void db_getString() { + + } + + @Override + public void db_putHex() { + + } + + @Override + public void db_getHex() { + + } + + @Override + public String personal_newAccount(String passphrase) { + return null; + } + + @Override + public String[] personal_listAccounts() { + return new String[0]; + } + + @Override + public String personal_importRawKey(String key, String passphrase) { + return null; + } + + @Override + public String personal_sendTransaction(CallArguments transactionArgs, String passphrase) throws Exception { + return null; + } + + @Override + public boolean personal_unlockAccount(String key, String passphrase, String duration) { + return false; + } + + @Override + public boolean personal_lockAccount(String key) { + return false; + } + + @Override + public String personal_dumpRawKey(String address) throws Exception { + return null; + } + + @Override + public XdagModule getXdagModule() { + return web3XdagModule.getXdagModule(); + } + + @Override + public String xdag_protocolVersion() { + return web3XdagModule.xdag_protocolVersion(); + } + + @Override + public Object xdag_syncing() { + return web3XdagModule.xdag_syncing(); + } + + @Override + public String xdag_coinbase() { + return web3XdagModule.xdag_coinbase(); + } + + @Override + public String xdag_blockNumber() { + return web3XdagModule.xdag_blockNumber(); + } + + @Override + public String xdag_getBalance(String address) throws Exception { + return web3XdagModule.xdag_getBalance(address); + } + + @Override + public String xdag_getTotalBalance() throws Exception { + return web3XdagModule.xdag_getTotalBalance(); + } + + @Override + public BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws Exception { + return web3XdagModule.xdag_getBlockByNumber(bnOrId,full); + } + + @Override + public BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception { + return web3XdagModule.xdag_getBlockByHash(blockHash,full); + } +} diff --git a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java index 301effdc..56c4cd9c 100644 --- a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java +++ b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java @@ -10,6 +10,13 @@ public class BlockResultDTO { // blockInfo // rawData + String height; + String data; + public BlockResultDTO(long height) { + this.height = Long.toHexString(height); + this.data = "hello"; + } + public static BlockResultDTO fromBlock(Block b, boolean raw) { diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java index 780fa500..c177fd09 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java @@ -2,7 +2,9 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +@JsonPropertyOrder({"jsonrpc", "id", "method", "result", "params", "error"}) public abstract class JsonRpcMessage { private final JsonRpcVersion version; diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java index f8fc1b85..2691db11 100644 --- a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java @@ -10,8 +10,6 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "method", visible = true) @JsonSubTypes({ -// @JsonSubTypes.Type(value = EthSubscribeRequest.class, name = "eth_subscribe"), -// @JsonSubTypes.Type(value = EthUnsubscribeRequest.class, name = "eth_unsubscribe"), }) public abstract class XdagJsonRpcRequest extends JsonRpcRequest { public XdagJsonRpcRequest( diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java index 1c76a274..4ae8ea0d 100644 --- a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java @@ -1,12 +1,5 @@ package io.xdag.rpc.modules; -import io.netty.channel.ChannelHandlerContext; -import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; -//import io.xdag.rpc.modules.eth.subscribe.EthSubscribeRequest; -//import io.xdag.rpc.modules.eth.subscribe.EthUnsubscribeRequest; public interface XdagJsonRpcRequestVisitor { -// JsonRpcResultOrError visit(EthUnsubscribeRequest request, ChannelHandlerContext ctx); -// -// JsonRpcResultOrError visit(EthSubscribeRequest request, ChannelHandlerContext ctx); } diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java index 0e4a0c9b..9cce248e 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java @@ -32,6 +32,8 @@ default String xdag_chainId() { String xdag_getBalance(String address) throws Exception; + String xdag_getTotalBalance() throws Exception; + default BlockResultDTO xdag_getTransactionByHash(String hash, Boolean full)throws Exception{ return xdag_getBlockByHash(hash,full); } diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java index 29a1f11f..35526b9d 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java @@ -2,8 +2,11 @@ import com.sun.jdi.LongValue; import io.xdag.Kernel; +import io.xdag.config.Config; +import io.xdag.config.MainnetConfig; import io.xdag.core.Block; import io.xdag.core.Blockchain; +import io.xdag.core.XdagState; import io.xdag.rpc.dto.BlockResultDTO; import io.xdag.rpc.modules.xdag.XdagModule; import io.xdag.utils.StringUtils; @@ -51,12 +54,20 @@ public String xdag_protocolVersion() { @Override public Object xdag_syncing() { long currentBlock = this.blockchain.getXdagStats().nmain; - long highestBlock = this.blockchain.getXdagStats().totalnmain; + long highestBlock = Math.max(this.blockchain.getXdagStats().totalnmain, currentBlock); - if (highestBlock < currentBlock){ - return false; + Config config = kernel.getConfig(); + if (config instanceof MainnetConfig) { + if (kernel.getXdagState() != XdagState.SYNC){ + return false; + } + } else { + if (kernel.getXdagState() != XdagState.STST) { + return false; + } } + SyncingResult s = new SyncingResult(); try { s.currentBlock = toQuantityJsonHex(currentBlock); @@ -96,9 +107,22 @@ public String xdag_getBalance(String address) throws Exception { return toQuantityJsonHex(balance); } + @Override + public String xdag_getTotalBalance() throws Exception { + double balance = amount2xdag(kernel.getBlockchain().getXdagStats().getBalance()); + return toQuantityJsonHex(balance); + } + @Override public BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws Exception { - return null; + System.out.println(bnOrId); + System.out.println(full); + if (full) { + System.out.println("hello"); + } + BlockResultDTO blockResultDTO = new BlockResultDTO(Integer.parseInt(bnOrId)); + + return blockResultDTO; } @Override diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java new file mode 100644 index 00000000..672168b9 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java @@ -0,0 +1,52 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonValue; +//import io.xdag.rpc.jsonrpc.JsonRpcResult; +//import io.xdag.rpc.utils.TypeConverter; +// +//import java.security.SecureRandom; +//import java.util.Arrays; +// +//public class SubscriptionId extends JsonRpcResult { +// private final byte[] id; +// +// @JsonCreator +// public SubscriptionId(String hexId) { +// this.id = TypeConverter.stringHexToByteArray(hexId); +// } +// +// public SubscriptionId() { +// this.id = new byte[16]; +// new SecureRandom().nextBytes(id); +// } +// +// public byte[] getId() { +// return Arrays.copyOf(id, id.length); +// } +// +// @Override +// public int hashCode() { +// return Arrays.hashCode(id); +// } +// +// @Override +// public boolean equals(Object o) { +// if (o == this) { +// return true; +// } +// +// if (!(o instanceof SubscriptionId)) { +// return false; +// } +// +// SubscriptionId other = (SubscriptionId) o; +// return Arrays.equals(this.id, other.id); +// } +// +// @JsonValue +// @SuppressWarnings("unused") +// private String serialize() { +// return TypeConverter.toJsonHex(id); +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java new file mode 100644 index 00000000..b3125962 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java @@ -0,0 +1,47 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//import com.fasterxml.jackson.annotation.JsonCreator; +//import com.fasterxml.jackson.annotation.JsonInclude; +//import com.fasterxml.jackson.annotation.JsonProperty; +//import io.netty.channel.ChannelHandlerContext; +//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +//import io.xdag.rpc.jsonrpc.JsonRpcVersion; +//import io.xdag.rpc.modules.XdagJsonRpcMethod; +//import io.xdag.rpc.modules.XdagJsonRpcRequest; +//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; +// +//import java.util.Objects; +// +//public class XDAGSubscribeRequest extends XdagJsonRpcRequest { +// +// private final XdagSubscribeParams params; +// +// @JsonCreator +// public XDAGSubscribeRequest( +// @JsonProperty("jsonrpc") JsonRpcVersion version, +// @JsonProperty("method") XdagJsonRpcMethod method, +// @JsonProperty("id") Integer id, +// @JsonProperty("params") XdagSubscribeParams params) { +// super(version, verifyMethod(method), Objects.requireNonNull(id)); +// this.params = Objects.requireNonNull(params); +// } +// +// @JsonInclude(JsonInclude.Include.NON_NULL) +// public XdagSubscribeParams getParams() { +// return params; +// } +// +// @Override +// public JsonRpcResultOrError accept(XdagJsonRpcRequestVisitor visitor, ChannelHandlerContext ctx) { +// return visitor.visit(this, ctx); +// } +// +// private static XdagJsonRpcMethod verifyMethod(XdagJsonRpcMethod method) { +// if (method != XdagJsonRpcMethod.ETH_SUBSCRIBE) { +// throw new IllegalArgumentException( +// "Wrong method mapped to eth_subscribe. Check JSON mapping configuration in JsonRpcRequest." +// ); +// } +// return method; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java new file mode 100644 index 00000000..e1d285b6 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java @@ -0,0 +1,4 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//public class XDAGUnsubscribeRequest { +//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java index bef665d9..124b8377 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java @@ -5,10 +5,10 @@ //import io.netty.channel.Channel; // // -//@JsonDeserialize(using = EthSubscribeParamsDeserializer.class) +//@JsonDeserialize(using = XdagSubscribeParamsDeserializer.class) //@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) //public interface XdagSubscribeParams { -// SubscriptionId accept(EthSubscribeParamsVisitor visitor, Channel channel); +// SubscriptionId accept(XdagSubscribeParamsVisitor visitor, Channel channel); //} // // diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java new file mode 100644 index 00000000..52945d35 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java @@ -0,0 +1,60 @@ +//package io.xdag.rpc.modules.xdag.subscribe; +// +//import com.fasterxml.jackson.core.JsonParser; +//import com.fasterxml.jackson.core.JsonToken; +//import com.fasterxml.jackson.databind.DeserializationContext; +//import com.fasterxml.jackson.databind.JsonDeserializer; +// +//import java.io.IOException; +//import java.util.HashMap; +// +//public class XdagSubscribeParamsDeserializer extends JsonDeserializer { +// +// private final HashMap> subscriptionTypes; +// +// public XdagSubscribeParamsDeserializer() { +// this.subscriptionTypes = new HashMap<>(); +//// this.subscriptionTypes.put("newHeads", EthSubscribeNewHeadsParams.class); +//// this.subscriptionTypes.put("logs", EthSubscribeLogsParams.class); +// } +// +// @Override +// public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { +// if (!p.isExpectedStartArrayToken()) { +// return ctxt.handleUnexpectedToken( +// XdagSubscribeParams.class, +// p.currentToken(), +// p, +// "xdag_subscribe parameters are expected to be arrays" +// ); +// } +// p.nextToken(); // skip '[' +// String subscriptionType = p.getText(); +// Class subscriptionTypeClass = subscriptionTypes.get(subscriptionType); +// p.nextToken(); +// XdagSubscribeParams params; +// if (p.isExpectedStartObjectToken()) { +// params = p.readValueAs(subscriptionTypeClass); +// p.nextToken(); +// } else { +// try { +// params = subscriptionTypeClass.newInstance(); +// } catch (InstantiationException | IllegalAccessException e) { +// return ctxt.handleInstantiationProblem( +// subscriptionTypeClass, +// null, +// e +// ); +// } +// } +// if (p.currentToken() != JsonToken.END_ARRAY) { +// return ctxt.handleUnexpectedToken( +// XdagSubscribeParams.class, +// p.currentToken(), +// p, +// "eth_subscribe can only have one object to configure subscription" +// ); +// } +// return params; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java index fc211d9f..a05f33cb 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java @@ -3,17 +3,17 @@ //import io.netty.channel.Channel; // //public interface XdagSubscribeParamsVisitor { -// /** -// * @param params new heads subscription request parameters. -// * @param channel a Netty channel to subscribe notifications to. -// * @return a subscription id which should be used as an unsubscribe parameter. -// */ -// SubscriptionId visit(EthSubscribeNewHeadsParams params, Channel channel); -// -// /** -// * @param params logs subscription request parameters. -// * @param channel a Netty channel to subscribe notifications to. -// * @return a subscription id which should be used as an unsubscribe parameter. -// */ -// SubscriptionId visit(EthSubscribeLogsParams params, Channel channel); +//// /** +//// * @param params new heads subscription request parameters. +//// * @param channel a Netty channel to subscribe notifications to. +//// * @return a subscription id which should be used as an unsubscribe parameter. +//// */ +//// SubscriptionId visit(XdagSubscribeNewHeadsParams params, Channel channel); +//// +//// /** +//// * @param params logs subscription request parameters. +//// * @param channel a Netty channel to subscribe notifications to. +//// * @return a subscription id which should be used as an unsubscribe parameter. +//// */ +//// SubscriptionId visit(XdagSubscribeLogsParams params, Channel channel); //} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java index 170ed7bb..3dc72b22 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java @@ -1,4 +1,4 @@ -package io.xdag.rpc.modules.xdag.subscribe; - -public interface XdagSubscriptionNotificationDTO { -} +//package io.xdag.rpc.modules.xdag.subscribe; +// +//public interface XdagSubscriptionNotificationDTO { +//} diff --git a/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java index edd36d28..7a90b54e 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java +++ b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java @@ -1,97 +1,97 @@ -///* -// * This file is part of RskJ -// * Copyright (C) 2018 RSK Labs Ltd. -// * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU Lesser General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. -// * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU Lesser General Public License for more details. -// * -// * You should have received a copy of the GNU Lesser General Public License -// * along with this program. If not, see . -// */ -//package io.xdag.rpc.netty; -// -//import io.netty.bootstrap.ServerBootstrap; -//import io.netty.channel.ChannelFuture; -//import io.netty.channel.ChannelInitializer; -//import io.netty.channel.ChannelPipeline; -//import io.netty.channel.EventLoopGroup; -//import io.netty.channel.nio.NioEventLoopGroup; -//import io.netty.channel.socket.SocketChannel; -//import io.netty.channel.socket.nio.NioServerSocketChannel; -//import io.netty.handler.codec.http.HttpObjectAggregator; -//import io.netty.handler.codec.http.HttpServerCodec; -//import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -// -//import javax.annotation.Nullable; -//import java.net.InetAddress; -// -//public class Web3WebSocketServer { -// private static final Logger logger = LoggerFactory.getLogger(Web3WebSocketServer.class); -// -// private final InetAddress host; -// private final int port; -// private final XdagJsonRpcHandler jsonRpcHandler; -// private final JsonRpcWeb3ServerHandler web3ServerHandler; -// private final EventLoopGroup bossGroup; -// private final EventLoopGroup workerGroup; -// private @Nullable ChannelFuture webSocketChannel; -// -// public Web3WebSocketServer( -// InetAddress host, -// int port, -// XdagJsonRpcHandler jsonRpcHandler, -// JsonRpcWeb3ServerHandler web3ServerHandler) { -// this.host = host; -// this.port = port; -// this.jsonRpcHandler = jsonRpcHandler; -// this.web3ServerHandler = web3ServerHandler; -// this.bossGroup = new NioEventLoopGroup(); -// this.workerGroup = new NioEventLoopGroup(); -// } -// -// public void start() { -// logger.info("RPC WebSocket enabled"); -// ServerBootstrap b = new ServerBootstrap(); -// b.group(bossGroup, workerGroup) -// .channel(NioServerSocketChannel.class) -// .childHandler(new ChannelInitializer() { -// @Override -// protected void initChannel(SocketChannel ch) throws Exception { -// ChannelPipeline p = ch.pipeline(); -// p.addLast(new HttpServerCodec()); -// p.addLast(new HttpObjectAggregator(1024 * 1024 * 5)); -// p.addLast(new WebSocketServerProtocolHandler("/websocket")); -// p.addLast(jsonRpcHandler); -// p.addLast(web3ServerHandler); -// p.addLast(new Web3ResultWebSocketResponseHandler()); -// } -// }); -// webSocketChannel = b.bind(host, port); -// try { -// webSocketChannel.sync(); -// } catch (InterruptedException e) { -// logger.error("The RPC WebSocket server couldn't be started", e); -// Thread.currentThread().interrupt(); -// } -// } -// -// public void stop() { -// try { -// webSocketChannel.channel().close().sync(); -// } catch (InterruptedException e) { -// logger.error("Couldn't stop the RPC WebSocket server", e); -// Thread.currentThread().interrupt(); -// } -// this.bossGroup.shutdownGracefully(); -// this.workerGroup.shutdownGracefully(); -// } -//} +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +package io.xdag.rpc.netty; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.Nullable; +import java.net.InetAddress; + +public class Web3WebSocketServer { + private static final Logger logger = LoggerFactory.getLogger(Web3WebSocketServer.class); + + private final InetAddress host; + private final int port; + private final XdagJsonRpcHandler jsonRpcHandler; + private final JsonRpcWeb3ServerHandler web3ServerHandler; + private final EventLoopGroup bossGroup; + private final EventLoopGroup workerGroup; + private @Nullable ChannelFuture webSocketChannel; + + public Web3WebSocketServer( + InetAddress host, + int port, + XdagJsonRpcHandler jsonRpcHandler, + JsonRpcWeb3ServerHandler web3ServerHandler) { + this.host = host; + this.port = port; + this.jsonRpcHandler = jsonRpcHandler; + this.web3ServerHandler = web3ServerHandler; + this.bossGroup = new NioEventLoopGroup(); + this.workerGroup = new NioEventLoopGroup(); + } + + public void start() { + logger.info("RPC WebSocket enabled"); + ServerBootstrap b = new ServerBootstrap(); + b.group(bossGroup, workerGroup) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ChannelPipeline p = ch.pipeline(); + p.addLast(new HttpServerCodec()); + p.addLast(new HttpObjectAggregator(1024 * 1024 * 5)); + p.addLast(new WebSocketServerProtocolHandler("/websocket")); + p.addLast(jsonRpcHandler); + p.addLast(web3ServerHandler); + p.addLast(new Web3ResultWebSocketResponseHandler()); + } + }); + webSocketChannel = b.bind(host, port); + try { + webSocketChannel.sync(); + } catch (InterruptedException e) { + logger.error("The RPC WebSocket server couldn't be started", e); + Thread.currentThread().interrupt(); + } + } + + public void stop() { + try { + webSocketChannel.channel().close().sync(); + } catch (InterruptedException e) { + logger.error("Couldn't stop the RPC WebSocket server", e); + Thread.currentThread().interrupt(); + } + this.bossGroup.shutdownGracefully(); + this.workerGroup.shutdownGracefully(); + } +} diff --git a/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java index f077d8a9..a904bfb9 100644 --- a/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java +++ b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java @@ -1,74 +1,70 @@ -//package io.xdag.rpc.netty; -// -//import io.netty.buffer.ByteBufHolder; -//import io.netty.buffer.ByteBufInputStream; -//import io.netty.channel.ChannelHandlerContext; -//import io.netty.channel.SimpleChannelInboundHandler; -//import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; -//import io.xdag.rpc.jsonrpc.JsonRpcBooleanResult; -//import io.xdag.rpc.jsonrpc.JsonRpcIdentifiableMessage; -//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; -//import io.xdag.rpc.modules.XdagJsonRpcRequest; -//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; -//import io.xdag.rpc.modules.eth.subscribe.EthSubscribeRequest; -//import io.xdag.rpc.modules.eth.subscribe.EthUnsubscribeRequest; -//import io.xdag.rpc.serialize.JsonRpcSerializer; -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -// -//import java.io.IOException; -// -//public class XdagJsonRpcHandler extends SimpleChannelInboundHandler -// implements XdagJsonRpcRequestVisitor { -// private static final Logger LOGGER = LoggerFactory.getLogger(XdagJsonRpcHandler.class); -// -//// private final EthSubscriptionNotificationEmitter emitter; -// private final JsonRpcSerializer serializer; -// -// public XdagJsonRpcHandler(JsonRpcSerializer serializer) { +package io.xdag.rpc.netty; + +import io.netty.buffer.ByteBufHolder; +import io.netty.buffer.ByteBufInputStream; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.xdag.rpc.jsonrpc.JsonRpcIdentifiableMessage; +import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; +import io.xdag.rpc.modules.XdagJsonRpcRequest; +import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; +import io.xdag.rpc.serialize.JsonRpcSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class XdagJsonRpcHandler extends SimpleChannelInboundHandler + implements XdagJsonRpcRequestVisitor { + private static final Logger LOGGER = LoggerFactory.getLogger(XdagJsonRpcHandler.class); + + private final JsonRpcSerializer serializer; + + public XdagJsonRpcHandler(JsonRpcSerializer serializer) { + this.serializer = serializer; + } +// public XdagJsonRpcHandler(EthSubscriptionNotificationEmitter emitter, JsonRpcSerializer serializer) { +// this.emitter = emitter; // this.serializer = serializer; // } -//// public XdagJsonRpcHandler(EthSubscriptionNotificationEmitter emitter, JsonRpcSerializer serializer) { -//// this.emitter = emitter; -//// this.serializer = serializer; -//// } -// -// @Override -// protected void channelRead0(ChannelHandlerContext ctx, ByteBufHolder msg) { -// try { -// XdagJsonRpcRequest request = serializer.deserializeRequest( -// new ByteBufInputStream(msg.copy().content()) -// ); -// -// // TODO(mc) we should support the ModuleDescription method filters -// JsonRpcResultOrError resultOrError = request.accept(this, ctx); -// JsonRpcIdentifiableMessage response = resultOrError.responseFor(request.getId()); -// ctx.writeAndFlush(new TextWebSocketFrame(serializer.serializeMessage(response))); -// return; -// } catch (IOException e) { -// LOGGER.trace("Not a known or valid JsonRpcRequest", e); -// } -// -// // delegate to the next handler if the message can't be matched to a known JSON-RPC request -// ctx.fireChannelRead(msg.retain()); -// } -// -// @Override -// public void channelInactive(ChannelHandlerContext ctx) throws Exception { -//// emitter.unsubscribe(ctx.channel()); -// super.channelInactive(ctx); -// } -// + + @Override + protected void channelRead0(ChannelHandlerContext ctx, ByteBufHolder msg) { + try { + XdagJsonRpcRequest request = serializer.deserializeRequest( + new ByteBufInputStream(msg.copy().content()) + ); + + // TODO(mc) we should support the ModuleDescription method filters + JsonRpcResultOrError resultOrError = request.accept(this, ctx); + JsonRpcIdentifiableMessage response = resultOrError.responseFor(request.getId()); + ctx.writeAndFlush(new TextWebSocketFrame(serializer.serializeMessage(response))); + return; + } catch (IOException e) { + LOGGER.trace("Not a known or valid JsonRpcRequest", e); + } + + // delegate to the next handler if the message can't be matched to a known JSON-RPC request + ctx.fireChannelRead(msg.retain()); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { +// emitter.unsubscribe(ctx.channel()); + super.channelInactive(ctx); + } + // @Override -// public JsonRpcResultOrError visit(EthUnsubscribeRequest request, ChannelHandlerContext ctx) { +// public JsonRpcResultOrError visit(XDAGUnsubscribeRequest request, ChannelHandlerContext ctx) { //// boolean unsubscribed = emitter.unsubscribe(request.getParams().getSubscriptionId()); //// return new JsonRpcBooleanResult(unsubscribed); // return null; // } // // @Override -// public JsonRpcResultOrError visit(EthSubscribeRequest request, ChannelHandlerContext ctx) { +// public JsonRpcResultOrError visit(XDAGSubscribeRequest request, ChannelHandlerContext ctx) { //// return request.getParams().accept(emitter, ctx.channel()); // return null; // } -//} +} diff --git a/src/main/java/io/xdag/utils/BasicUtils.java b/src/main/java/io/xdag/utils/BasicUtils.java index 0526e488..cf17758c 100644 --- a/src/main/java/io/xdag/utils/BasicUtils.java +++ b/src/main/java/io/xdag/utils/BasicUtils.java @@ -23,6 +23,7 @@ */ package io.xdag.utils; +import cn.hutool.core.codec.Base64; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; @@ -54,60 +55,73 @@ public static BigInteger getDiffByHash(byte[] hash) { return ans; } +// public static String hash2Address(byte[] hash) { +// hash = Arrays.reverse(hash); +// char[] newcha = new char[32]; +// int c = 0; +// int d; +// int h; +// for (int i = d = h = 0; i < 32; i++) { +// if (d < 6) { +// d += 8; +// c <<= 8; +// c |= Byte.toUnsignedInt(hash[h]); +// h++; +// } +// d -= 6; +// int index = (c >> d) & 0x3f; +// newcha[i] = bit2mime[index]; +// } +// return String.copyValueOf(newcha); +// } + public static String hash2Address(byte[] hash) { hash = Arrays.reverse(hash); - char[] newcha = new char[32]; - int c = 0; - int d; - int h; - for (int i = d = h = 0; i < 32; i++) { - if (d < 6) { - d += 8; - c <<= 8; - c |= Byte.toUnsignedInt(hash[h]); - h++; - } - d -= 6; - int index = (c >> d) & 0x3f; - newcha[i] = bit2mime[index]; - } - return String.copyValueOf(newcha); + byte[] addr = new byte[24]; + System.arraycopy(hash,0,addr,0,24); + return Base64.encode(addr); } - - /** - * 返回低192bit的hash hashlow - * - * @param address - * 256bit hash - * @return 前64位置0的hashlow - */ public static byte[] address2Hash(String address) { - byte[] hashlow = new byte[32]; - int i, c, d, n; - int h = 0, j = 0; - for (int e = n = i = 0; i < 32; ++i) { - do { - if ((c = Byte.toUnsignedInt((byte) address.charAt(h++))) == 0) { - return null; - } - d = Byte.toUnsignedInt(mime2bits[c]); - } while ((d & 0xC0) != 0); - e <<= 6; - e |= d; - n += 6; - - if (n >= 8) { - n -= 8; - hashlow[j++] = (byte) (e >> n); - } - } - - for (i = 0; i < 8; i++) { - hashlow[j++] = 0; - } - return Arrays.reverse(hashlow); + byte[] ret = Base64.decode(address); + byte[] res = new byte[32]; + System.arraycopy(Arrays.reverse(ret),0,res,8,24); + return res; } +// /** +// * 返回低192bit的hash hashlow +// * +// * @param address +// * 256bit hash +// * @return 前64位置0的hashlow +// */ +// public static byte[] address2Hash(String address) { +// byte[] hashlow = new byte[32]; +// int i, c, d, n; +// int h = 0, j = 0; +// for (int e = n = i = 0; i < 32; ++i) { +// do { +// if ((c = Byte.toUnsignedInt((byte) address.charAt(h++))) == 0) { +// return null; +// } +// d = Byte.toUnsignedInt(mime2bits[c]); +// } while ((d & 0xC0) != 0); +// e <<= 6; +// e |= d; +// n += 6; +// +// if (n >= 8) { +// n -= 8; +// hashlow[j++] = (byte) (e >> n); +// } +// } +// +// for (i = 0; i < 8; i++) { +// hashlow[j++] = 0; +// } +// return Arrays.reverse(hashlow); +// } + // convert xdag to cheato public static long xdag2amount(double input) { double amount = Math.floor(input); diff --git a/src/main/resources/rpc_modules.conf b/src/main/resources/rpc_modules.conf new file mode 100644 index 00000000..4b91b3f9 --- /dev/null +++ b/src/main/resources/rpc_modules.conf @@ -0,0 +1,96 @@ +rpc { + providers { + web { + cors = "localhost" + http { + enabled = true + bind_address = localhost + hosts = [] + port = 4444 + # 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. + linger_time = -1 + } + ws { + enabled = true + bind_address = localhost + port = 4445 + } + } + } + + # Enabled RPC Modules. If the module is NOT in the list, and mark as "enabled", the rpc calls will be discard. + # It is possible to enable/disable a particular method in a module + # { + # name: "evm", + # version: "1.0", + # enabled: "true", + # methods: { + # enabled: [ "evm_snapshot", "evm_revert" ], + # disabled: [ "evm_reset", "evm_increaseTime" ] + # } + # } + modules = [ + { + name: "xdag", + version: "1.0", + enabled: "true", + }, +; { +; name: "eth", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "net", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "rpc", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "web3", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "evm", +; version: "1.0", +; enabled: "true" +; }, +; { +; name: "sco", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "txpool", +; version: "1.0", +; enabled: "true", +; }, +; { +; name: "personal", +; version: "1.0", +; enabled: "true" +; }, +; { +; name: "debug", +; version: "1.0", +; enabled: "true" +; }, +; { +; name: "trace", +; version: "1.0", +; enabled: "true" +; }, +; { +; name: "rsk", +; version: "1.0", +; enabled: "true" +; } + ] +} diff --git a/src/main/resources/xdag-testnet.config b/src/main/resources/xdag-testnet.config index bba68628..dcb29f9e 100644 --- a/src/main/resources/xdag-testnet.config +++ b/src/main/resources/xdag-testnet.config @@ -32,3 +32,61 @@ maxMinerPerAccount = 256 password = root whiteIPs = + +modules = [ + { + name: "eth", + version: "1.0", + enabled: "true", + }, + { + name: "net", + version: "1.0", + enabled: "true", + }, + { + name: "rpc", + version: "1.0", + enabled: "true", + }, + { + name: "web3", + version: "1.0", + enabled: "true", + }, + { + name: "evm", + version: "1.0", + enabled: "true" + }, + { + name: "sco", + version: "1.0", + enabled: "true", + }, + { + name: "txpool", + version: "1.0", + enabled: "true", + }, + { + name: "personal", + version: "1.0", + enabled: "true" + }, + { + name: "debug", + version: "1.0", + enabled: "true" + }, + { + name: "trace", + version: "1.0", + enabled: "true" + }, + { + name: "rsk", + version: "1.0", + enabled: "true" + } + ] diff --git a/src/test/java/io/xdag/core/BlockchainTest.java b/src/test/java/io/xdag/core/BlockchainTest.java index 3da4dfba..a21dd1a2 100644 --- a/src/test/java/io/xdag/core/BlockchainTest.java +++ b/src/test/java/io/xdag/core/BlockchainTest.java @@ -70,6 +70,9 @@ public class BlockchainTest { Kernel kernel; DatabaseFactory dbFactory; + BigInteger private_1 = new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16); + BigInteger private_2 = new BigInteger("10a55f0c18c46873ddbf9f15eddfc06f10953c601fd144474131199e04148046", 16); + @Before public void setUp() throws Exception { config.getNodeSpec().setStoreDir(root.newFolder().getAbsolutePath()); @@ -125,7 +128,7 @@ public void startCheckMain() { @Test public void testAddressBlock() { - ECKeyPair key = Keys.createEcKeyPair(); + ECKeyPair key = ECKeyPair.create(private_1); Block addressBlock = generateAddressBlock(config, key, new Date().getTime()); MockBlockchain blockchain = new MockBlockchain(kernel); ImportResult result = blockchain.tryToConnect(addressBlock); @@ -142,7 +145,7 @@ public void testAddressBlock() { public void testExtraBlock() throws ParseException { // Date date = fastDateFormat.parse("2020-09-20 23:45:00"); long generateTime = 1600616700000L; - ECKeyPair key = Keys.createEcKeyPair(); + ECKeyPair key = ECKeyPair.create(private_1); MockBlockchain blockchain = new MockBlockchain(kernel); XdagTopStatus stats = blockchain.getXdagTopStatus(); assertNotNull(stats); @@ -188,8 +191,8 @@ public void testExtraBlock() throws ParseException { @Test public void testTransactionBlock() throws ParseException { - ECKeyPair addrKey = Keys.createEcKeyPair(); - ECKeyPair poolKey = Keys.createEcKeyPair(); + ECKeyPair addrKey = ECKeyPair.create(private_1); + ECKeyPair poolKey = ECKeyPair.create(private_2); // Date date = fastDateFormat.parse("2020-09-20 23:45:00"); long generateTime = 1600616700000L; // 1. add one address block @@ -315,8 +318,8 @@ public void testTransactionBlock() throws ParseException { public void testCanUseInput() throws ParseException { // Date date = fastDateFormat.parse("2020-09-20 23:45:00"); long generateTime = 1600616700000L; - ECKeyPair fromKey = Keys.createEcKeyPair(); - ECKeyPair toKey = Keys.createEcKeyPair(); + ECKeyPair fromKey = ECKeyPair.create(private_1); + ECKeyPair toKey = ECKeyPair.create(private_2); Block fromAddrBlock = generateAddressBlock(config, fromKey, generateTime); Block toAddrBlock = generateAddressBlock(config, toKey, generateTime); @@ -420,11 +423,11 @@ public void testOriginFork() throws ParseException { BigInteger privateKey = new BigInteger(privString, 16); - String firstDiff = "aedbac91e1"; - String secondDiff = "d936e19b89"; + String firstDiff = "60b6a7744b"; + String secondDiff = "b20217d6e2"; - ECKeyPair addrKey = ECKeyPair.create(privateKey); - ECKeyPair poolKey = ECKeyPair.create(privateKey); + ECKeyPair addrKey = ECKeyPair.create(private_1); + ECKeyPair poolKey = ECKeyPair.create(private_2); long generateTime = 1600616700000L; // 1. add one address block Block addressBlock = generateAddressBlock(config, addrKey,generateTime); diff --git a/src/test/java/io/xdag/core/ExtraBlockTest.java b/src/test/java/io/xdag/core/ExtraBlockTest.java index 7f701e57..b6c1afa6 100644 --- a/src/test/java/io/xdag/core/ExtraBlockTest.java +++ b/src/test/java/io/xdag/core/ExtraBlockTest.java @@ -68,6 +68,9 @@ public class ExtraBlockTest { long expectedExtraBlocks = 5; + BigInteger private_1 = new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16); + BigInteger private_2 = new BigInteger("10a55f0c18c46873ddbf9f15eddfc06f10953c601fd144474131199e04148046", 16); + @Before public void setUp() throws Exception { config.getNodeSpec().setStoreDir(root.newFolder().getAbsolutePath()); @@ -124,8 +127,8 @@ public void testExtraBlockReUse() throws ParseException { String privString = "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"; BigInteger privateKey = new BigInteger(privString, 16); - ECKeyPair addrKey = ECKeyPair.create(privateKey); - ECKeyPair poolKey = ECKeyPair.create(privateKey); + ECKeyPair addrKey = ECKeyPair.create(private_1); + ECKeyPair poolKey = ECKeyPair.create(private_2); // Date date = fastDateFormat.parse("2020-09-20 23:45:00"); long generateTime = 1600616700000L; // 1. add one address block diff --git a/src/test/java/io/xdag/core/RandomXSyncTest.java b/src/test/java/io/xdag/core/RandomXSyncTest.java index 81653d9e..11d40a6f 100644 --- a/src/test/java/io/xdag/core/RandomXSyncTest.java +++ b/src/test/java/io/xdag/core/RandomXSyncTest.java @@ -66,7 +66,7 @@ public class RandomXSyncTest { Config config = new DevnetConfig(); public static FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); - private final String privString = "421d725da10c056a955d2444a5a043b1a5d4515db126b8631806a8ccbda93369"; + private final String privString = "10a55f0c18c46873ddbf9f15eddfc06f10953c601fd144474131199e04148046"; private final BigInteger privateKey = new BigInteger(privString, 16); private long forkHeight; @@ -76,7 +76,7 @@ public void init() { RandomXConstants.SEEDHASH_EPOCH_TESTNET_BLOCKS = 64; RandomXConstants.RANDOMX_TESTNET_FORK_HEIGHT = 128; RandomXConstants.SEEDHASH_EPOCH_TESTNET_LAG = 4; - forkHeight = 2; + forkHeight = 3; } diff --git a/src/test/java/io/xdag/core/RewardTest.java b/src/test/java/io/xdag/core/RewardTest.java index 4a1df999..a43386ca 100644 --- a/src/test/java/io/xdag/core/RewardTest.java +++ b/src/test/java/io/xdag/core/RewardTest.java @@ -66,6 +66,10 @@ public class RewardTest { Kernel kernel; DatabaseFactory dbFactory; + String privString = "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"; + BigInteger privateKey = new BigInteger(privString, 16); + + class MockBlockchain extends BlockchainImpl { public MockBlockchain(Kernel kernel) { @@ -110,8 +114,6 @@ public void setUp() throws Exception { @Test public void testReward() throws ParseException { - String privString = "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4"; - BigInteger privateKey = new BigInteger(privString, 16); RandomXConstants.RANDOMX_TESTNET_FORK_HEIGHT = 16000; RandomXConstants.SEEDHASH_EPOCH_TESTNET_BLOCKS = 16; diff --git a/src/test/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponseTest.java b/src/test/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponseTest.java new file mode 100644 index 00000000..9c31b5e4 --- /dev/null +++ b/src/test/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponseTest.java @@ -0,0 +1,24 @@ +package io.xdag.rpc.jsonrpc; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + + +public class JsonRpcResultResponseTest { + private ObjectMapper serializer = new ObjectMapper(); + + @Test + public void serializeResponseWithResult() throws IOException { + String message = "{\"jsonrpc\":\"2.0\",\"id\":48,\"result\":true}"; + assertEquals( + serializer.writeValueAsString( + new JsonRpcResultResponse(48, new JsonRpcBooleanResult(true)) + ), + message + ); + } +} From 3266442348b68c52c782f83fa290b2131b8a2de4 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Tue, 25 May 2021 11:50:13 +0800 Subject: [PATCH 03/11] fix sign problem --- src/test/java/io/xdag/BlockBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/io/xdag/BlockBuilder.java b/src/test/java/io/xdag/BlockBuilder.java index 5a3a2212..8f3b58c1 100644 --- a/src/test/java/io/xdag/BlockBuilder.java +++ b/src/test/java/io/xdag/BlockBuilder.java @@ -46,6 +46,7 @@ public static Block generateAddressBlock(Config config, ECKeyPair key, long xdag return b; } + // TODO:set nonce means this block is a mining block, the mining param need to set true public static Block generateExtraBlock(Config config, ECKeyPair key, long xdagTime, List
pendings) { Block b = new Block(config, xdagTime, null, pendings, true, null, null, -1); b.signOut(key); @@ -54,6 +55,7 @@ public static Block generateExtraBlock(Config config, ECKeyPair key, long xdagTi return b; } + // TODO:set nonce means this block is a mining block, the mining param need to set true public static Block generateExtraBlockGivenRandom(Config config, ECKeyPair key, long xdagTime, List
pendings, String randomS) { Block b = new Block(config, xdagTime, null, pendings, true, null, null, -1); b.signOut(key); From 2db2dbd69f52e2c3525966945b3b601f4432ec7b Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Tue, 25 May 2021 21:59:57 +0800 Subject: [PATCH 04/11] merge mnemonic-wallet --- README.md | 63 ++- pom.xml | 19 + script/xdag.sh | 17 + src/main/java/io/xdag/Bootstrap.java | 53 +- src/main/java/io/xdag/Kernel.java | 16 +- src/main/java/io/xdag/Launcher.java | 69 ++- src/main/java/io/xdag/cli/Commands.java | 16 +- src/main/java/io/xdag/cli/XdagCli.java | 486 +++++++++++++++++ .../XdagOption.java} | 39 +- .../java/io/xdag/config/AbstractConfig.java | 4 +- src/main/java/io/xdag/config/Constants.java | 4 + .../java/io/xdag/config/DevnetConfig.java | 2 + .../java/io/xdag/config/MainnetConfig.java | 2 + .../java/io/xdag/config/TestnetConfig.java | 2 + .../java/io/xdag/config/spec/WalletSpec.java | 1 + src/main/java/io/xdag/consensus/XdagPow.java | 4 +- .../java/io/xdag/core/BlockchainImpl.java | 10 +- src/main/java/io/xdag/core/SimpleEncoder.java | 95 +++- src/main/java/io/xdag/crypto/Aes.java | 102 ++++ src/main/java/io/xdag/crypto/Credentials.java | 87 --- src/main/java/io/xdag/crypto/Keys.java | 79 +-- .../xdag/mine/manager/AwardManagerImpl.java | 18 +- .../java/io/xdag/utils/ByteArrayWrapper.java | 4 + .../java/io/xdag/utils/SimpleDecoder.java | 155 ++++++ src/main/java/io/xdag/utils/SystemUtil.java | 10 + src/main/java/io/xdag/wallet/Bip39Wallet.java | 58 -- .../java/io/xdag/wallet/Bip44WalletUtils.java | 80 --- src/main/java/io/xdag/wallet/Wallet.java | 516 ++++++++++++------ src/main/java/io/xdag/wallet/WalletFile.java | 467 ---------------- .../java/io/xdag/wallet/WalletManager.java | 73 --- src/main/java/io/xdag/wallet/WalletUtils.java | 215 +------- src/test/java/io/xdag/cli/XdagCliTest.java | 464 ++++++++++++++++ .../java/io/xdag/config/DevnetConfigTest.java | 23 + .../io/xdag/config/MainnetConfigTest.java | 23 + .../io/xdag/config/TestnetConfigTest.java | 23 + .../java/io/xdag/core/BlockchainTest.java | 26 +- .../java/io/xdag/core/ExtraBlockTest.java | 26 +- .../java/io/xdag/core/RandomXSyncTest.java | 15 +- src/test/java/io/xdag/core/RewardTest.java | 29 +- .../java/io/xdag/crypto/CredentialsTest.java | 51 -- .../java/io/xdag/crypto/ECRecoverTest.java | 87 --- src/test/java/io/xdag/crypto/KeysTest.java | 59 -- src/test/java/io/xdag/crypto/SampleKeys.java | 4 +- .../io/xdag/mine/miner/MinerConnectTest.java | 30 +- .../io/xdag/wallet/Bip44WalletUtilsTest.java | 109 ---- .../java/io/xdag/wallet/WalletFileTest.java | 87 --- .../io/xdag/wallet/WalletManagerTest.java | 66 --- src/test/java/io/xdag/wallet/WalletTest.java | 193 +++++-- .../java/io/xdag/wallet/WalletUtilsTest.java | 245 +++------ 49 files changed, 2286 insertions(+), 2040 deletions(-) create mode 100755 script/xdag.sh create mode 100644 src/main/java/io/xdag/cli/XdagCli.java rename src/main/java/io/xdag/{wallet/CipherException.java => cli/XdagOption.java} (70%) create mode 100644 src/main/java/io/xdag/crypto/Aes.java delete mode 100644 src/main/java/io/xdag/crypto/Credentials.java create mode 100644 src/main/java/io/xdag/utils/SimpleDecoder.java delete mode 100644 src/main/java/io/xdag/wallet/Bip39Wallet.java delete mode 100644 src/main/java/io/xdag/wallet/Bip44WalletUtils.java delete mode 100644 src/main/java/io/xdag/wallet/WalletFile.java delete mode 100644 src/main/java/io/xdag/wallet/WalletManager.java create mode 100644 src/test/java/io/xdag/cli/XdagCliTest.java delete mode 100644 src/test/java/io/xdag/crypto/CredentialsTest.java delete mode 100644 src/test/java/io/xdag/crypto/ECRecoverTest.java delete mode 100644 src/test/java/io/xdag/wallet/Bip44WalletUtilsTest.java delete mode 100644 src/test/java/io/xdag/wallet/WalletFileTest.java delete mode 100644 src/test/java/io/xdag/wallet/WalletManagerTest.java diff --git a/README.md b/README.md index 40e7a6b3..f3399f18 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ - [System environment](#system-environment) - [Installation and usage](#installation-and-usage) - [Develop](#develop) + - [XDAG Mars Project](#XDAG-Mars-Project) - [Code](#code) - [Contribution](#contribution) - [Sponsorship](#sponsorship) @@ -35,21 +36,59 @@ The Private Chain Building Tutorial helps you to build a private-chain for testi XDAGJ already has the basic functions as a pool, and the follow-up work is to improve the stability of the system while optimizing the existing code. It is important to adopt excellent blockchain technology for XDAGJ. -The main work of the next stage includes but not limited +### XDAG Mars Project -- Optimize the XDAG consensus process and synchronization protocol -- LibP2P is used to replace the DNET network and gradually improve the degree of decentralization as long as the system stability allows. -- Open API interface, provide black box testing. -- Add a commission to the transaction. -- Use BIPxx and other specifications to improve the existing public and private key and address generation methods, and provide a more convenient and universal key storage method. -- Add snapshot function to solve the problem of slow loading speed of historical main block. -- Optimize the address block structure to avoid dust attacks. +The XDAG Mars Project is divided into four stages: -At the same time, we are also actively providing more application scenarios for XDAG, including but not limited. +#### Exploration phase: XDAGJ testnet is online (online, in beta) + +- [x] Deploy XDAGJ test network environment, open beta + +- [x] Implement the RandomX algorithm + +- [x] Implement the libp2p network protocol + +- [x] Testnet blockchain browser + +- [x] Test coin acquisition + + +#### Landing phase: XDAGJ mainnet is online + +- [ ] Improve test cases: write test cases for existing functions + +- [ ] Improve the log function: provide a relatively complete log service to facilitate trouble shooting + +- [ ] Optimize synchronization protocol: ameliorate the existing synchronization protocol and improve synchronization efficiency + +- [ ] Implement the snapshot function: solve the problem of long time-consuming loading data caused by too many historical blocks + +- [ ] Implement the RPC function: access to Web3j, realize the standardization of the interface + +- [ ] Improve the mining protocol: introduce the more mature Stratum protocol + +- [ ] Lightweight wallet application: connect to MateMask, join the browser wallet + +- [ ] Standardize the format of public and private keys, follow the BIPXX specification, and add mnemonic words to generate public and private key pairs + +#### Expansion phase: XDAGJ & EVM + +- [ ] Improve the address block structure and increase the handling fee + +- [ ] Optimize and improve mobile wallets to improve user experience + +- [ ] Support smart contracts, implement EVM that supports Solidity, and be compatible with Ethereum smart contracts + +- [ ] Lower the threshold of mining pool users and gradually open the whitelist to achieve complete decentralization + +#### Prosperity phase: XDAGJ & DeFi + +- [ ] Implement cross-chain protocols, compatible with access to multiple blockchain systems, to achieve intercommunication between XDAG and other chain worlds + +- [ ] Implement the oracle function + +- [ ] Join a distributed exchange -- Explore the possibility of using neo4j as the storage layer to provide a visual DAG storage. -- Explore a way to add a virtual machine to XDAG to implement smart contracts and improve the usability of the system. -- Explore effective cross-chain solutions to break the closed ecology of XDAG. ## Code diff --git a/pom.xml b/pom.xml index 3bae316f..9ad25efd 100644 --- a/pom.xml +++ b/pom.xml @@ -288,6 +288,12 @@ 2.8.0 + + commons-cli + commons-cli + 1.4 + + com.google.guava guava @@ -449,6 +455,19 @@ + + com.github.stefanbirkner + system-rules + 1.19.0 + test + + + junit + junit-dep + + + + org.assertj assertj-core diff --git a/script/xdag.sh b/script/xdag.sh new file mode 100755 index 00000000..0a935ac0 --- /dev/null +++ b/script/xdag.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +XDAG_VERSION="0.4.2" +XDAG_JARNAME="xdagj-${XDAG_VERSION}-shaded.jar" +XDAG_OPTS="-t" + +# Linux Java Home +JAVA_HOME="/usr/local/java/" + +# MacOS Java Home +#JAVA_HOME=/usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home/ + +# default JVM options +JAVA_OPTS="--enable-preview -server -Xms1g -Xmx1g" + +# start kernel +java ${JAVA_OPTS} -cp ${XDAG_JARNAME} io.xdag.Bootstrap "$@" \ No newline at end of file diff --git a/src/main/java/io/xdag/Bootstrap.java b/src/main/java/io/xdag/Bootstrap.java index be578bd5..d1aa5d82 100644 --- a/src/main/java/io/xdag/Bootstrap.java +++ b/src/main/java/io/xdag/Bootstrap.java @@ -23,59 +23,12 @@ */ package io.xdag; -import io.xdag.config.*; -import io.xdag.wallet.OldWallet; -import lombok.extern.slf4j.Slf4j; +import io.xdag.cli.XdagCli; -@Slf4j public class Bootstrap { - public static Config getConfig(String[] args) throws Exception { -// if (args == null || args.length == 0) { -// throw new RuntimeException("getConfig(args) args is empty! "); -// } - Config config = new MainnetConfig(); - for (String arg : args) { - switch (arg) { - case "-t": - config = new TestnetConfig(); - break; - } - } - config.changePara(args); - config.setDir(); - //logPoolInfo(oldConfig); - - // init keys - config.initKeys(); - return config; - } - - public static void logPoolInfo(Config config) { - log.info( - "矿池节点地址 :[{}:{}], 矿池服务地址:[{}:{}],相关配置信息: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()); - } - public static void main(String[] args) throws Exception { - Config config = getConfig(args); - - - // if dnet_keys.dat and wallet.dat exist - OldWallet wallet = new OldWallet(); - - Kernel kernel = new Kernel(config, wallet); - // default start kernel - kernel.testStart(); + XdagCli.main(args); } + } diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index bfb7e1d1..4b5ff070 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -71,7 +71,7 @@ import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; import io.xdag.rpc.serialize.JsonRpcSerializer; import io.xdag.utils.XdagTime; -import io.xdag.wallet.OldWallet; +import io.xdag.wallet.Wallet; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -88,7 +88,7 @@ public class Kernel { protected Status status = Status.STOPPED; protected Config config; - protected OldWallet wallet; + protected Wallet wallet; protected DatabaseFactory dbFactory; protected BlockStore blockStore; protected OrphanPool orphanPool; @@ -136,7 +136,7 @@ public class Kernel { protected JsonRpcWeb3FilterHandler jsonRpcWeb3FilterHandler; protected JacksonBasedRpcSerializer jacksonBasedRpcSerializer; - public Kernel(Config config, OldWallet wallet) { + public Kernel(Config config, Wallet wallet) { this.config = config; this.wallet = wallet; // 启动的时候就是在初始化 @@ -171,11 +171,13 @@ public synchronized void testStart() throws Exception { // ==================================== // wallet init // ==================================== + // if (wallet == null) { - wallet = new OldWallet(); - wallet.init(this.config); +// wallet = new OldWallet(); +// wallet.init(this.config); + log.info("Wallet init."); -// } + dbFactory = new RocksdbFactory(this.config); blockStore = new BlockStore( @@ -210,7 +212,7 @@ public synchronized void testStart() throws Exception { // 如果是第一次启动,则新建第一个地址块 if (xdagStats.getOurLastBlockHash() == null) { firstAccount = new Block(config, XdagTime.getCurrentTimestamp(), null, null, false, null,null, -1); - firstAccount.signOut(wallet.getDefKey().ecKey); + firstAccount.signOut(wallet.getDefKey()); poolMiner = new Miner(firstAccount.getHash()); xdagStats.setOurLastBlockHash(firstAccount.getHashLow()); if(xdagStats.getGlobalMiner() == null) { diff --git a/src/main/java/io/xdag/Launcher.java b/src/main/java/io/xdag/Launcher.java index 30a0646c..a8b09375 100644 --- a/src/main/java/io/xdag/Launcher.java +++ b/src/main/java/io/xdag/Launcher.java @@ -23,17 +23,27 @@ */ package io.xdag; +import io.xdag.config.Config; +import io.xdag.config.MainnetConfig; +import io.xdag.config.TestnetConfig; +import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.cli.*; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; @Slf4j +@Getter +@Setter public class Launcher { + private final Options options = new Options(); + private String password = null; + private Config config; + /** * Here we make sure that all shutdown hooks will be executed in the order of * registration. This is necessary to be manually maintained because @@ -68,4 +78,57 @@ private static synchronized void shutdownHook() { LogManager.shutdown(); } + /** + * Adds a supported option. + */ + protected void addOption(Option option) { + options.addOption(option); + } + + /** + * Parses options from the given arguments. + */ + protected CommandLine parseOptions(String[] args) throws ParseException { + if (args == null || args.length == 0 ) { + return null; + } + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = parser.parse(getOptions(), args); + + return cmd; + } + + protected Config buildConfig(String[] args) throws Exception { + Config config = new MainnetConfig(); + for (String arg : args) { + switch (arg) { + case "-t" -> config = new TestnetConfig(); + } + } + config.changePara(args); + config.setDir(); + logPoolInfo(config); + + // init keys + config.initKeys(); + + return config; + } + + 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()); + } + } diff --git a/src/main/java/io/xdag/cli/Commands.java b/src/main/java/io/xdag/cli/Commands.java index 0ddcf440..efa042c7 100644 --- a/src/main/java/io/xdag/cli/Commands.java +++ b/src/main/java/io/xdag/cli/Commands.java @@ -164,13 +164,13 @@ public String xfer(double sendAmount, byte[] address, String remark) { int index = pair.getKey(); Block block = pair.getValue(); if (remain.get() <= block.getInfo().getAmount()) { - ourBlocks.put(new Address(block.getHashLow(), XDAG_FIELD_IN, remain.get()), kernel.getWallet().getKeyByIndex(index)); + ourBlocks.put(new Address(block.getHashLow(), XDAG_FIELD_IN, remain.get()), kernel.getWallet().getAccounts().get(index)); remain.set(0); return true; } else { if (block.getInfo().getAmount() > 0) { remain.set(remain.get() - block.getInfo().getAmount()); - ourBlocks.put(new Address(block.getHashLow(), XDAG_FIELD_IN, block.getInfo().getAmount()), kernel.getWallet().getKeyByIndex(index)); + ourBlocks.put(new Address(block.getHashLow(), XDAG_FIELD_IN, block.getInfo().getAmount()), kernel.getWallet().getAccounts().get(index)); return false; } return false; @@ -213,7 +213,7 @@ private List createTransactionBlock(Map ourKey // 保证key的唯一性 Set keysPerBlock = new HashSet<>(); // 放入defkey - keysPerBlock.add(kernel.getWallet().getDefKey().ecKey); + keysPerBlock.add(kernel.getWallet().getDefKey()); // base count a block
int base = 1 + 1 + 2 + hasRemark; @@ -239,7 +239,7 @@ private List createTransactionBlock(Map ourKey // 清空keys,准备下一个 keys = new HashMap<>(); keysPerBlock = new HashSet<>(); - keysPerBlock.add(kernel.getWallet().getDefKey().ecKey); + keysPerBlock.add(kernel.getWallet().getDefKey()); base = 1 + 1 + 2 + hasRemark; amount = 0; } @@ -262,7 +262,7 @@ private BlockWrapper createTransaction(byte[] to, long amount, Map argsList = new ArrayList<>(); + for (String arg : args) { + switch (arg) { + case "-t" -> config = new TestnetConfig(); + default -> argsList.add(arg); + } + } + String[] newArgs = argsList.toArray(new String[0]); + // parse common options + CommandLine cmd = null; + try { + cmd = parseOptions(newArgs); + } catch (ParseException exception) { + System.err.println("Parsing Failed:" + exception.getMessage()); + } + + if(cmd == null) { + start(); + } else if (cmd.hasOption(XdagOption.HELP.toString())) { + printHelp(); + } else if (cmd.hasOption(XdagOption.VERSION.toString())) { + printVersion(); + } else if (cmd.hasOption(XdagOption.ACCOUNT.toString())) { + String action = cmd.getOptionValue(XdagOption.ACCOUNT.toString()).trim(); + switch (action) { + case "init" -> initHDAccount(); + case "create" -> createAccount(); + case "list" -> listAccounts(); + default -> System.out.println("No Action!"); + } + } else if (cmd.hasOption(XdagOption.CHANGE_PASSWORD.toString())) { + changePassword(); + } else if (cmd.hasOption(XdagOption.DUMP_PRIVATE_KEY.toString())) { + dumpPrivateKey(cmd.getOptionValue(XdagOption.DUMP_PRIVATE_KEY.toString()).trim()); + } else if (cmd.hasOption(XdagOption.IMPORT_PRIVATE_KEY.toString())) { + importPrivateKey(cmd.getOptionValue(XdagOption.IMPORT_PRIVATE_KEY.toString()).trim()); + } else if (cmd.hasOption(XdagOption.IMPORT_MNEMONIC.toString())) { + importMnemonic(cmd.getOptionValue(XdagOption.IMPORT_MNEMONIC.toString()).trim()); + } else if (cmd.hasOption(XdagOption.CONVERT_OLD_WALLET.toString())) { + File file = new File(cmd.getOptionValue(XdagOption.CONVERT_OLD_WALLET.toString()).trim()); + convertOldWallet(file); + } + } + + protected void printHelp() { + HelpFormatter formatter = new HelpFormatter(); + formatter.setWidth(200); + formatter.printHelp("./xdag.sh [options]", getOptions()); + } + + protected void printVersion() { + System.out.println(Constants.CLIENT_VERSION); + } + + protected void start() throws IOException { + // create/unlock wallet + Wallet wallet = loadWallet().exists() ? loadAndUnlockWallet() : createNewWallet(); + if (wallet == null) { + return; + } + + if (!wallet.isHdWalletInitialized()) { + initializedHdSeed(wallet, System.out); + } + + // create a new account if the wallet is empty + List accounts = wallet.getAccounts(); + if (accounts.isEmpty()) { + ECKeyPair key = wallet.addAccountWithNextHdKey(); + wallet.flush(); + System.out.println("New Address:" + BytesUtils.toHexString(Keys.toBytesAddress(key))); + } + + // start kernel + try { + startKernel(getConfig(), wallet); + } catch (Exception e) { + System.err.println("Uncaught exception during kernel startup:" + e.getMessage()); + exit(-1); + } + } + + /** + * Starts the kernel. + */ + protected Kernel startKernel(Config config, Wallet wallet) throws Exception { + Kernel kernel = new Kernel(config, wallet); + kernel.testStart(); + return kernel; + } + + protected void initHDAccount() { + // create/unlock wallet + Wallet wallet; + if(loadWallet().exists()) { + wallet = loadAndUnlockWallet(); + } else { + wallet = createNewWallet(); + } + + if (wallet == null) { + return; + } + if (!wallet.isHdWalletInitialized()) { + initializedHdSeed(wallet, System.out); + } else { + System.out.println("HD Wallet Account already init."); + } + } + + protected void createAccount() { + Wallet wallet = loadAndUnlockWallet(); + if(Objects.nonNull(wallet) && !wallet.isHdWalletInitialized()) { + System.out.println("Please init HD Wallet account first!"); + return; + } + ECKeyPair key = wallet.addAccountWithNextHdKey(); + if (wallet.flush()) { + System.out.println("New Address:" + BytesUtils.toHexString(Keys.toBytesAddress(key))); + System.out.println("PublicKey:" + BytesUtils.toHexString(key.getPublicKey().toByteArray())); + } + } + + protected void listAccounts() { + Wallet wallet = loadAndUnlockWallet(); + List accounts = wallet.getAccounts(); + + if (accounts.isEmpty()) { + System.out.println("Account Missing"); + } else { + for (int i = 0; i < accounts.size(); i++) { + System.out.println("Address:" + i + " " + BytesUtils.toHexString(Keys.toBytesAddress(accounts.get(i)))); + } + } + } + + protected void changePassword() { + Wallet wallet = loadAndUnlockWallet(); + if(wallet.isUnlocked()) { + String newPassword = readNewPassword("EnterNewPassword", "ReEnterNewPassword"); + if (newPassword == null) { + return; + } + wallet.changePassword(newPassword); + boolean isFlushed = wallet.flush(); + if (!isFlushed) { + System.out.println("Wallet File Cannot Be Updated"); + return; + } + System.out.println("Password Changed Successfully!"); + } + } + + protected void exit(int code) { + System.exit(code); + } + + protected void dumpPrivateKey(String address) { + Wallet wallet = loadAndUnlockWallet(); + byte[] addressBytes = BytesUtils.hexStringToBytes(address); + ECKeyPair account = wallet.getAccount(addressBytes); + if (account == null) { + System.out.println("Address Not In Wallet"); + } else { + System.out.println("Private:" + BytesUtils.toHexString(account.getPrivateKey().toByteArray())); + } + System.out.println("Private Dump Successfully!"); + } + + protected boolean importPrivateKey(String key) { + Wallet wallet = loadAndUnlockWallet(); + byte[] keyBytes = BytesUtils.hexStringToBytes(key); + ECKeyPair account = ECKeyPair.create(keyBytes); + + boolean accountAdded = wallet.addAccount(account); + if (!accountAdded) { + System.out.println("Private Key Already In Wallet"); + return false; + } + + boolean walletFlushed = wallet.flush(); + if (!walletFlushed) { + System.out.println("Wallet File Cannot Be Updated"); + return false; + } + + System.out.println("Address:" + BytesUtils.toHexString(Keys.toBytesAddress(account))); + System.out.println("PublicKey:" + BytesUtils.toHexString(account.getPublicKey().toByteArray())); + System.out.println("Private Key Imported Successfully!"); + return true; + } + + protected boolean importMnemonic(String mnemonic) { + Wallet wallet = loadAndUnlockWallet(); + + if(wallet.isHdWalletInitialized()) { + System.out.println("HDWallet Mnemonic Already In Wallet"); + return false; + } + + if(!MnemonicUtils.validateMnemonic(mnemonic)) { + System.out.println("Wrong Mnemonic"); + return false; + } + + // default add one hd key + createAccount(); + + if (!wallet.flush()) { + System.out.println("HDWallet File Cannot Be Updated"); + return false; + } + System.out.println("HDWallet Mnemonic Imported Successfully!"); + return true; + } + + protected boolean convertOldWallet(File file) { + if(!file.exists()) { + System.out.println("File:" + file.getName() + " not exists."); + return false; + } + List keyList = readOldWallet(file); + for(ECKeyPair key : keyList) { + System.out.println("PrivateKey:" + BytesUtils.toHexString(key.getPrivateKey().toByteArray())); + System.out.println(" PublicKey:" + BytesUtils.toHexString(key.getPublicKey().toByteArray())); + System.out.println(" Address:" + BytesUtils.toHexString(Keys.toBytesAddress(key))); + } + System.out.println("Old Wallet Converted Successfully!"); + return true; + } + + private List readOldWallet(File walletDatFile) { + byte[] priv32Encrypted = new byte[32]; + int keysNum = 0; + List keyList = new ArrayList<>(); + try (FileInputStream fileInputStream = new FileInputStream(walletDatFile)) { + while (fileInputStream.read(priv32Encrypted) != -1) { + byte[] priv32 = Native.uncrypt_wallet_key(priv32Encrypted, keysNum++); + ECKeyPair ecKey = ECKeyPair.create(Numeric.toBigInt(priv32)); + keyList.add(ecKey); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return keyList; + } + + public Wallet loadWallet() { + return new Wallet(getConfig()); + } + + public Wallet loadAndUnlockWallet() { + Wallet wallet = loadWallet(); + if (getPassword() == null) { + if (wallet.unlock("")) { + setPassword(""); + } else { + setPassword(readPassword()); + } + } + + if (!wallet.unlock(getPassword())) { + System.err.println("Invalid password"); + } + + return wallet; + } + + /** + * Create a new wallet with a new password + */ + public Wallet createNewWallet() { + String newPassword = readNewPassword("EnterNewPassword:", "ReEnterNewPassword:"); + if (newPassword == null) { + return null; + } + + setPassword(newPassword); + Wallet wallet = loadWallet(); + + if (!wallet.unlock(newPassword) || !wallet.flush()) { + System.err.println("Create New WalletError"); + System.exit(-1); + return null; + } + + return wallet; + } + + /** + * Read a new password from input and require confirmation + */ + public String readNewPassword(String newPasswordMessageKey, String reEnterNewPasswordMessageKey) { + String newPassword = readPassword(newPasswordMessageKey); + String newPasswordRe = readPassword(reEnterNewPasswordMessageKey); + + if (!newPassword.equals(newPasswordRe)) { + System.err.println("ReEnter NewPassword Incorrect"); + System.exit(-1); + return null; + } + + return newPassword; + } + + /** + * Reads a line from the console. + */ + public String readLine(String prompt) { + if (prompt != null) { + System.out.print(prompt); + System.out.flush(); + } + + return scanner.nextLine(); + } + + public boolean initializedHdSeed(Wallet wallet, PrintStream printer) { + if (wallet.isUnlocked() && !wallet.isHdWalletInitialized()) { + // HD Mnemonic + printer.println("HdWallet Initializing..."); + byte[] initialEntropy = new byte[16]; + SecureRandomUtils.secureRandom().nextBytes(initialEntropy); + String phrase = MnemonicUtils.generateMnemonic(initialEntropy); + printer.println("HdWallet Mnemonic:"+ phrase); + + String repeat = readLine("HdWallet Mnemonic Repeat:"); + repeat = String.join(" ", repeat.trim().split("\\s+")); + + if (!repeat.equals(phrase)) { + printer.println("HdWallet Initialized Failure"); + return false; + } + + wallet.initializeHdWallet(phrase); + wallet.flush(); + printer.println("HdWallet Initialized Successfully!"); + return true; + } + return false; + } + + public String readPassword(String prompt) { + Console console = System.console(); + if (console == null) { + if (prompt != null) { + System.out.print(prompt); + System.out.flush(); + } + return scanner.nextLine(); + } + return new String(console.readPassword(prompt)); + } + + public String readPassword() { + return readPassword("Please enter your password: "); + } +} \ No newline at end of file diff --git a/src/main/java/io/xdag/wallet/CipherException.java b/src/main/java/io/xdag/cli/XdagOption.java similarity index 70% rename from src/main/java/io/xdag/wallet/CipherException.java rename to src/main/java/io/xdag/cli/XdagOption.java index 6aea0196..1fb8d0d2 100644 --- a/src/main/java/io/xdag/wallet/CipherException.java +++ b/src/main/java/io/xdag/cli/XdagOption.java @@ -21,20 +21,37 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.wallet; +package io.xdag.cli; -/** Cipher exception wrapper. */ -public class CipherException extends Exception { +public enum XdagOption { - public CipherException(String message) { - super(message); - } + HELP("help"), + + VERSION("version"), + + ACCOUNT("account"), + + CHANGE_PASSWORD("changepassword"), + + PASSWORD("password"), + + DUMP_PRIVATE_KEY("dumpprivatekey"), - public CipherException(Throwable cause) { - super(cause); + IMPORT_PRIVATE_KEY("importprivatekey"), + + IMPORT_MNEMONIC("importmnemonic"), + + CONVERT_OLD_WALLET("convertoldwallet"); + + private final String name; + + XdagOption(String s) { + name = s; } - public CipherException(String message, Throwable cause) { - super(message, cause); + @Override + public String toString() { + return this.name; } -} \ No newline at end of file + +} diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index c4878acf..40bc2192 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -124,7 +124,7 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa // ========================= // Wallet spec // ========================= - + protected String walletFilePath; // ========================= // Xdag spec @@ -291,7 +291,7 @@ public void changePara(String[] args) { this.poolTag = StringUtils.substring(args[i+1], 0, 31); break; default: - System.out.println("Illegal instruction"); + log.error("Illegal instruction"); } } } diff --git a/src/main/java/io/xdag/config/Constants.java b/src/main/java/io/xdag/config/Constants.java index a7b42781..cf25f9c3 100644 --- a/src/main/java/io/xdag/config/Constants.java +++ b/src/main/java/io/xdag/config/Constants.java @@ -53,4 +53,8 @@ public class Constants { /** 每一轮的确认数是16 */ public static final int CONFIRMATIONS_COUNT = 16; public static final int MAIN_BIG_PERIOD_LOG = 21; + + public static final String WALLET_FILE_NAME = "wallet.data"; + + public static final String CLIENT_VERSION = "0.4.3"; } diff --git a/src/main/java/io/xdag/config/DevnetConfig.java b/src/main/java/io/xdag/config/DevnetConfig.java index c7aec33b..f1c921e6 100644 --- a/src/main/java/io/xdag/config/DevnetConfig.java +++ b/src/main/java/io/xdag/config/DevnetConfig.java @@ -43,6 +43,8 @@ public DevnetConfig() { this.dnetKeyFile = this.rootDir+"/dnet_keys.bin"; this.walletKeyFile = this.rootDir+"/wallet-testnet.dat"; + + this.walletFilePath = this.rootDir + "/wallet/" + Constants.WALLET_FILE_NAME; } } diff --git a/src/main/java/io/xdag/config/MainnetConfig.java b/src/main/java/io/xdag/config/MainnetConfig.java index 219fd4f3..0fa0fe41 100644 --- a/src/main/java/io/xdag/config/MainnetConfig.java +++ b/src/main/java/io/xdag/config/MainnetConfig.java @@ -42,6 +42,8 @@ public MainnetConfig() { this.dnetKeyFile = this.rootDir+"/dnet_keys.bin"; this.walletKeyFile = this.rootDir+"/wallet.dat"; + + this.walletFilePath = this.rootDir + "/wallet/" + Constants.WALLET_FILE_NAME; } } diff --git a/src/main/java/io/xdag/config/TestnetConfig.java b/src/main/java/io/xdag/config/TestnetConfig.java index 4dedf91f..1c1ca4d4 100644 --- a/src/main/java/io/xdag/config/TestnetConfig.java +++ b/src/main/java/io/xdag/config/TestnetConfig.java @@ -44,6 +44,8 @@ public TestnetConfig() { this.dnetKeyFile = this.rootDir+"/dnet_keys.bin"; this.walletKeyFile = this.rootDir+"/wallet-testnet.dat"; + + this.walletFilePath = this.rootDir + "/wallet/" + Constants.WALLET_FILE_NAME; } } diff --git a/src/main/java/io/xdag/config/spec/WalletSpec.java b/src/main/java/io/xdag/config/spec/WalletSpec.java index 27414340..ce4e0eaf 100644 --- a/src/main/java/io/xdag/config/spec/WalletSpec.java +++ b/src/main/java/io/xdag/config/spec/WalletSpec.java @@ -28,4 +28,5 @@ */ public interface WalletSpec { String getWalletKeyFile(); + String getWalletFilePath(); } diff --git a/src/main/java/io/xdag/consensus/XdagPow.java b/src/main/java/io/xdag/consensus/XdagPow.java index 4fd6f9a5..34f4b2e4 100644 --- a/src/main/java/io/xdag/consensus/XdagPow.java +++ b/src/main/java/io/xdag/consensus/XdagPow.java @@ -184,7 +184,7 @@ public Block generateRandomXBlock(long sendTime) { taskIndex++; Block block = blockchain.createNewBlock(null, null, true, null); - block.signOut(kernel.getWallet().getDefKey().ecKey); + block.signOut(kernel.getWallet().getDefKey()); minShare = RandomUtils.nextBytes(32); block.setNonce(minShare); @@ -208,7 +208,7 @@ public Block generateBlock(long sendTime) { taskIndex++; Block block = blockchain.createNewBlock(null, null, true, null); - block.signOut(kernel.getWallet().getDefKey().ecKey); + block.signOut(kernel.getWallet().getDefKey()); minShare = RandomUtils.nextBytes(32); block.setNonce(minShare); diff --git a/src/main/java/io/xdag/core/BlockchainImpl.java b/src/main/java/io/xdag/core/BlockchainImpl.java index bfd1eb4a..b2c04856 100644 --- a/src/main/java/io/xdag/core/BlockchainImpl.java +++ b/src/main/java/io/xdag/core/BlockchainImpl.java @@ -40,7 +40,7 @@ import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; import io.xdag.wallet.KeyInternalItem; -import io.xdag.wallet.OldWallet; +import io.xdag.wallet.Wallet; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -79,7 +79,7 @@ public Thread newThread(@Nonnull Runnable r) { } }; - private final OldWallet wallet; + private final Wallet wallet; private final BlockStore blockStore; /** 非Extra orphan存放 */ private final OrphanPool orphanPool; @@ -714,7 +714,7 @@ public Block createNewBlock(Map pairs, List
to, boo assert pairs != null; List keys = new ArrayList<>(Set.copyOf(pairs.values())); for (int i = 0; i < keys.size(); i++) { - if (keys.get(i).equals(wallet.getDefKey().ecKey)) { + if (keys.get(i).equals(wallet.getDefKey())) { defKeyIndex = i; } } @@ -1130,12 +1130,12 @@ public boolean canUseInput(Block block) { } public boolean checkMineAndAdd(Block block) { - List ourkeys = wallet.getKey_internal(); + List ourkeys = wallet.getAccounts(); // 输出签名只有一个 ECDSASignature signature = block.getOutsig(); // 遍历所有key for (int i = 0; i < ourkeys.size(); i++) { - ECKeyPair ecKey = ourkeys.get(i).ecKey; + ECKeyPair ecKey = ourkeys.get(i); byte[] publicKeyBytes = Sign.publicKeyBytesFromPrivate(ecKey.getPrivateKey(), true); byte[] digest = BytesUtils.merge( block.getSubRawData(block.getOutsigIndex() - 2), publicKeyBytes); diff --git a/src/main/java/io/xdag/core/SimpleEncoder.java b/src/main/java/io/xdag/core/SimpleEncoder.java index c948b038..f906d127 100644 --- a/src/main/java/io/xdag/core/SimpleEncoder.java +++ b/src/main/java/io/xdag/core/SimpleEncoder.java @@ -23,8 +23,11 @@ */ package io.xdag.core; +import io.xdag.utils.exception.SimpleCodecException; + import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; public class SimpleEncoder { private final ByteArrayOutputStream out; @@ -57,6 +60,68 @@ public void write(byte[] input) { } } + public int getWriteFieldIndex() { + return getWriteIndex() / 32; + } + + public void writeBoolean(boolean b) { + out.write(b ? 1 : 0); + } + + public void writeByte(byte b) { + out.write(b); + } + + public void writeShort(short s) { + out.write(0xFF & (s >>> 8)); + out.write(0xFF & s); + } + + public void writeInt(int i) { + out.write(0xFF & (i >>> 24)); + out.write(0xFF & (i >>> 16)); + out.write(0xFF & (i >>> 8)); + out.write(0xFF & i); + } + + public void writeString(String s) { + writeBytes(s.getBytes(StandardCharsets.UTF_8)); + } + + public void writeLong(long l) { + int i1 = (int) (l >>> 32); + int i2 = (int) l; + + writeInt(i1); + writeInt(i2); + } + + /** + * Encode a byte array. + * + * @param bytes + * the byte array to encode + * @param vlq + * should always be true unless we're providing pre-mainnet support. + */ + public void writeBytes(byte[] bytes, boolean vlq) { + if (vlq) { + writeSize(bytes.length); + } else { + writeInt(bytes.length); + } + + try { + out.write(bytes); + } catch (IOException e) { + throw new SimpleCodecException(e); + } + } + + public void writeBytes(byte[] bytes) { + writeBytes(bytes, true); + } + public byte[] toBytes() { return out.toByteArray(); } @@ -65,7 +130,33 @@ private int getWriteIndex() { return out.size(); } - public int getWriteFieldIndex() { - return getWriteIndex() / 32; + /** + * Writes a size into the output byte array. + * + * @param size + * @throws IllegalArgumentException + * when the input size is negative + */ + protected void writeSize(int size) { + if (size < 0) { + throw new IllegalArgumentException("Size can't be negative: " + size); + } else if (size > 0x0FFFFFFF) { + throw new IllegalArgumentException("Size can't be larger than 0x0FFFFFFF: " + size); + } + + int[] buf = new int[4]; + int i = buf.length; + do { + buf[--i] = size & 0x7f; + size >>>= 7; + } while (size > 0); + + while (i < buf.length) { + if (i != buf.length - 1) { + out.write((byte) (buf[i++] | 0x80)); + } else { + out.write((byte) buf[i++]); + } + } } } diff --git a/src/main/java/io/xdag/crypto/Aes.java b/src/main/java/io/xdag/crypto/Aes.java new file mode 100644 index 00000000..8db3ce50 --- /dev/null +++ b/src/main/java/io/xdag/crypto/Aes.java @@ -0,0 +1,102 @@ +/* + * 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 org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CBCBlockCipher; +import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; + +public class Aes { + + private Aes() { + } + + private static byte[] cipherData(PaddedBufferedBlockCipher cipher, byte[] data) + throws DataLengthException, IllegalStateException, InvalidCipherTextException { + // create output buffer + int size = cipher.getOutputSize(data.length); + byte[] buf = new byte[size]; + + // process data + int length1 = cipher.processBytes(data, 0, data.length, buf, 0); + int length2 = cipher.doFinal(buf, length1); + int length = length1 + length2; + + // copy buffer to result, without padding + byte[] result = new byte[length]; + System.arraycopy(buf, 0, result, 0, result.length); + + return result; + } + + /** + * Encrypt data with AES/CBC/PKCS5Padding. + * + * @param raw + * @param key + * @param iv + * @return + */ + public static byte[] encrypt(byte[] raw, byte[] key, byte[] iv) { + + try { + PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine())); + CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv); + aes.init(true, params); + + return cipherData(aes, raw); + } catch (DataLengthException | IllegalArgumentException | IllegalStateException + | InvalidCipherTextException e) { + throw new RuntimeException(e); + } + + } + + /** + * Decrypt data with AES/CBC/PKCS5Padding + * + * @param encrypted + * @param key + * @param iv + * @return + */ + public static byte[] decrypt(byte[] encrypted, byte[] key, byte[] iv) { + try { + PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine())); + CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv); + aes.init(false, params); + + return cipherData(aes, encrypted); + } catch (DataLengthException | IllegalArgumentException | IllegalStateException + | InvalidCipherTextException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/io/xdag/crypto/Credentials.java b/src/main/java/io/xdag/crypto/Credentials.java deleted file mode 100644 index 0bb1a79c..00000000 --- a/src/main/java/io/xdag/crypto/Credentials.java +++ /dev/null @@ -1,87 +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 io.xdag.utils.Numeric; - -import java.util.Objects; - -/** Credentials wrapper. */ -public class Credentials { - - private final ECKeyPair ecKeyPair; - private final String address; - - private Credentials(ECKeyPair ecKeyPair, String address) { - this.ecKeyPair = ecKeyPair; - this.address = address; - } - - public ECKeyPair getEcKeyPair() { - return ecKeyPair; - } - - public String getAddress() { - return address; - } - - public static Credentials create(ECKeyPair ecKeyPair) { - String address = Numeric.prependHexPrefix(Keys.getAddress(ecKeyPair)); - return new Credentials(ecKeyPair, address); - } - - public static Credentials create(String privateKey, String publicKey) { - return create(new ECKeyPair(Numeric.toBigInt(privateKey), Numeric.toBigInt(publicKey))); - } - - public static Credentials create(String privateKey) { - return create(ECKeyPair.create(Numeric.toBigInt(privateKey))); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Credentials that = (Credentials) o; - - if (!Objects.equals(ecKeyPair, that.ecKeyPair)) { - return false; - } - - return Objects.equals(address, that.address); - } - - @Override - public int hashCode() { - int result = ecKeyPair != null ? ecKeyPair.hashCode() : 0; - result = 31 * result + (address != null ? address.hashCode() : 0); - return result; - } -} - diff --git a/src/main/java/io/xdag/crypto/Keys.java b/src/main/java/io/xdag/crypto/Keys.java index 8744c558..85e64e15 100644 --- a/src/main/java/io/xdag/crypto/Keys.java +++ b/src/main/java/io/xdag/crypto/Keys.java @@ -36,14 +36,8 @@ /** Crypto key utilities. */ public class Keys { - - public static final int PRIVATE_KEY_SIZE = 32; public static final int PUBLIC_KEY_SIZE = 64; - - public static final int ADDRESS_SIZE = 160; - public static final int ADDRESS_LENGTH_IN_HEX = ADDRESS_SIZE >> 2; static final int PUBLIC_KEY_LENGTH_IN_HEX = PUBLIC_KEY_SIZE << 1; - public static final int PRIVATE_KEY_LENGTH_IN_HEX = PRIVATE_KEY_SIZE << 1; static { if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { @@ -94,76 +88,13 @@ public static ECKeyPair createEcKeyPair(SecureRandom random) { return ECKeyPair.create(keyPair); } - public static String getAddress(ECKeyPair ecKeyPair) { - return getAddress(ecKeyPair.getPublicKey()); + public static byte[] toBytesAddress(ECKeyPair key) { + return Hash.sha256hash160(key.getPublicKey().toByteArray()); } - public static String getAddress(BigInteger publicKey) { - return getAddress( - Numeric.toHexStringWithPrefixZeroPadded(publicKey, PUBLIC_KEY_LENGTH_IN_HEX)); - } - - public static String getAddress(String publicKey) { - String publicKeyNoPrefix = Numeric.cleanHexPrefix(publicKey); - - if (publicKeyNoPrefix.length() < PUBLIC_KEY_LENGTH_IN_HEX) { - publicKeyNoPrefix = - Strings.zeros(PUBLIC_KEY_LENGTH_IN_HEX - publicKeyNoPrefix.length()) - + publicKeyNoPrefix; - } - String hash = Hash.sha256(publicKeyNoPrefix); - return hash.substring(hash.length() - ADDRESS_LENGTH_IN_HEX); // right most 160 bits - } - - public static byte[] getAddress(byte[] publicKey) { - byte[] hash = Hash.sha256(publicKey); - return Arrays.copyOfRange(hash, hash.length - 20, hash.length); // right most 160 bits - } - -// /** -// * Checksum address encoding as per EIP-55. -// * -// * @param address a valid hex encoded address -// * @return hex encoded checksum address -// */ -// public static String toChecksumAddress(String address) { -// String lowercaseAddress = Numeric.cleanHexPrefix(address).toLowerCase(); -// String addressHash = Numeric.cleanHexPrefix(Hash.sha3String(lowercaseAddress)); -// -// StringBuilder result = new StringBuilder(lowercaseAddress.length() + 2); -// -// result.append("0x"); -// -// for (int i = 0; i < lowercaseAddress.length(); i++) { -// if (Integer.parseInt(String.valueOf(addressHash.charAt(i)), 16) >= 8) { -// result.append(String.valueOf(lowercaseAddress.charAt(i)).toUpperCase()); -// } else { -// result.append(lowercaseAddress.charAt(i)); -// } -// } -// -// return result.toString(); -// } - - public static byte[] serialize(ECKeyPair ecKeyPair) { - byte[] privateKey = Numeric.toBytesPadded(ecKeyPair.getPrivateKey(), PRIVATE_KEY_SIZE); - byte[] publicKey = Numeric.toBytesPadded(ecKeyPair.getPublicKey(), PUBLIC_KEY_SIZE); - - byte[] result = Arrays.copyOf(privateKey, PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE); - System.arraycopy(publicKey, 0, result, PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE); - return result; - } - - public static ECKeyPair deserialize(byte[] input) { - if (input.length != PRIVATE_KEY_SIZE + PUBLIC_KEY_SIZE) { - throw new RuntimeException("Invalid input key size"); - } - - BigInteger privateKey = Numeric.toBigInt(input, 0, PRIVATE_KEY_SIZE); - BigInteger publicKey = Numeric.toBigInt(input, PRIVATE_KEY_SIZE, PUBLIC_KEY_SIZE); - - return new ECKeyPair(privateKey, publicKey); + public static String toBase58Address(ECKeyPair key) { + byte[] addrBytes = toBytesAddress(key); + return Base58.encode(addrBytes); } } diff --git a/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java b/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java index 6b8315fa..6034d212 100644 --- a/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java +++ b/src/main/java/io/xdag/mine/manager/AwardManagerImpl.java @@ -38,12 +38,12 @@ import io.xdag.crypto.ECKeyPair; import io.xdag.mine.MinerChannel; import io.xdag.utils.*; -import io.xdag.wallet.OldWallet; import io.xdag.Kernel; import io.xdag.consensus.Task; import io.xdag.mine.miner.Miner; import io.xdag.mine.miner.MinerStates; +import io.xdag.wallet.Wallet; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; @@ -75,7 +75,7 @@ public class AwardManagerImpl implements AwardManager, Runnable { private MinerManager minerManager; private final Kernel kernel; private final Blockchain blockchain; - private final OldWallet xdagWallet; + private final Wallet wallet; private ArrayList diff = new ArrayList<>(); private ArrayList prev_diff = new ArrayList<>(); @@ -84,7 +84,7 @@ public AwardManagerImpl(Kernel kernel) { this.kernel = kernel; this.config = kernel.getConfig(); this.blockchain = kernel.getBlockchain(); - this.xdagWallet = kernel.getWallet(); + this.wallet = kernel.getWallet(); this.poolMiner = kernel.getPoolMiner(); this.minerManager = kernel.getMinerManager(); init(); @@ -173,7 +173,7 @@ private static double diffToPay(double sum, int diffCount) { } public void init() { - log.debug("容器初始化"); + log.debug("AwardManager init."); // 容器的初始化 for (int i = 0; i < 16; i++) { blockHashs.add(null); @@ -327,7 +327,7 @@ public int payMiners(long time) { // 决定一个区块是否需要再有一个签名字段 // todo 这里不够严谨把 如果时第三把第四把呢 - if (xdagWallet.getKey_internal().size() - 1 == keyPos) { + if (wallet.getAccounts().size() - 1 == keyPos) { payminersPerBlock = 11; } else { payminersPerBlock = 9; @@ -470,7 +470,7 @@ public void doPayments(byte[] hash, int paymentsPerBlock, PayData payData, int k ArrayList
receipt = new ArrayList<>(paymentsPerBlock - 1); Map inputMap = new HashMap<>(); Address input = new Address(hash, XDAG_FIELD_IN); - ECKeyPair inputKey = xdagWallet.getKeyByIndex(keyPos); + ECKeyPair inputKey = wallet.getAccount(keyPos); inputMap.put(input, inputKey); long payAmount = 0L; /** @@ -539,14 +539,14 @@ public void transaction(byte[] hashLow, ArrayList
receipt, long payAmou } Map inputMap = new HashMap<>(); Address input = new Address(hashLow, XDAG_FIELD_IN, payAmount); - ECKeyPair inputKey = xdagWallet.getKeyByIndex(keypos); + ECKeyPair inputKey = wallet.getAccount(keypos); inputMap.put(input, inputKey); Block block = blockchain.createNewBlock(inputMap, receipt, false, null); - if (inputKey.equals(xdagWallet.getDefKey().ecKey)) { + if (inputKey.equals(wallet.getDefKey())) { block.signOut(inputKey); } else { block.signIn(inputKey); - block.signOut(xdagWallet.getDefKey().ecKey); + block.signOut(wallet.getDefKey()); } log.debug("pay block hash【{}】", Hex.toHexString(block.getHash())); diff --git a/src/main/java/io/xdag/utils/ByteArrayWrapper.java b/src/main/java/io/xdag/utils/ByteArrayWrapper.java index 6bea389d..53edc5e4 100644 --- a/src/main/java/io/xdag/utils/ByteArrayWrapper.java +++ b/src/main/java/io/xdag/utils/ByteArrayWrapper.java @@ -39,6 +39,10 @@ public byte[] getData() { return data; } + public static ByteArrayWrapper of(byte[] data) { + return new ByteArrayWrapper(data); + } + @Override public boolean equals(Object other) { if (!(other instanceof ByteArrayWrapper)) { diff --git a/src/main/java/io/xdag/utils/SimpleDecoder.java b/src/main/java/io/xdag/utils/SimpleDecoder.java new file mode 100644 index 00000000..30157f0a --- /dev/null +++ b/src/main/java/io/xdag/utils/SimpleDecoder.java @@ -0,0 +1,155 @@ +/* + * 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; + +import io.xdag.utils.exception.SimpleCodecException; + +import java.io.UnsupportedEncodingException; + +public class SimpleDecoder { + private static final String ENCODING = "UTF-8"; + + private final byte[] in; + private final int from; + private final int to; + + private int index; + + public SimpleDecoder(byte[] in) { + this(in, 0, in.length); + } + + public SimpleDecoder(byte[] in, int from) { + this(in, from, in.length); + } + + public SimpleDecoder(byte[] in, int from, int to) { + this.in = in; + this.from = from; + this.to = to; + this.index = from; + } + + public boolean readBoolean() { + require(1); + return in[index++] != 0; + } + + public byte readByte() { + require(1); + return in[index++]; + } + + public short readShort() { + require(2); + return (short) ((in[index++] & 0xFF) << 8 | (in[index++] & 0xFF)); + } + + public int readInt() { + require(4); + return in[index++] << 24 | (in[index++] & 0xFF) << 16 | (in[index++] & 0xFF) << 8 | (in[index++] & 0xFF); + } + + public long readLong() { + int i1 = readInt(); + int i2 = readInt(); + + return (unsignedInt(i1) << 32) | unsignedInt(i2); + } + + /** + * Decode a byte array. + * + * @param vlq + * should always be true unless we're providing pre-mainnet support. + */ + public byte[] readBytes(boolean vlq) { + int len = vlq ? readSize() : readInt(); + + require(len); + byte[] buf = new byte[len]; + System.arraycopy(in, index, buf, 0, len); + index += len; + + return buf; + } + + public byte[] readBytes() { + return readBytes(true); + } + + public String readString() { + try { + return new String(readBytes(), ENCODING); + } catch (UnsupportedEncodingException e) { + throw new SimpleCodecException(e); + } + } + + public int getReadIndex() { + return index; + } + + /** + * Reads size from the input. + * + * @return + */ + protected int readSize() { + int size = 0; + for (int i = 0; i < 4; i++) { + require(1); + byte b = in[index++]; + + size = (size << 7) | (b & 0x7F); + if ((b & 0x80) == 0) { + break; + } + } + return size; + } + + /** + * Checks if the required bytes is satisfied. + * + * @param n + */ + protected void require(int n) { + if (to - index < n) { + String msg = String.format("input [%d, %d], require: [%d %d]", from, to, index, index + n); + throw new IndexOutOfBoundsException(msg); + } + } + + /** + * Re-interprets an integer as unsigned integer. + * + * @param i + * an integer + * @return the unsigned value, represented in long + */ + protected long unsignedInt(int i) { + return i & 0x00000000ffffffffL; + } +} diff --git a/src/main/java/io/xdag/utils/SystemUtil.java b/src/main/java/io/xdag/utils/SystemUtil.java index 353ab936..fc56cdbb 100644 --- a/src/main/java/io/xdag/utils/SystemUtil.java +++ b/src/main/java/io/xdag/utils/SystemUtil.java @@ -23,6 +23,7 @@ */ package io.xdag.utils; +import java.nio.file.FileSystems; import java.util.Locale; public class SystemUtil { @@ -86,4 +87,13 @@ public static String getOsArch() { return System.getProperty("os.arch"); } + /** + * Check if current OS is POSIX compliant. + * + * @return whether current OS is POSIX compliant + */ + public static boolean isPosix() { + return FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); + } + } diff --git a/src/main/java/io/xdag/wallet/Bip39Wallet.java b/src/main/java/io/xdag/wallet/Bip39Wallet.java deleted file mode 100644 index 2ec2ecd9..00000000 --- a/src/main/java/io/xdag/wallet/Bip39Wallet.java +++ /dev/null @@ -1,58 +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.wallet; - -/** Data class encapsulating a BIP-39 compatible Xdag wallet. */ -public class Bip39Wallet { - /** Path to wallet file. */ - private final String filename; - - /** Generated BIP-39 mnemonic for the wallet. */ - private final String mnemonic; - - public Bip39Wallet(String filename, String mnemonic) { - this.filename = filename; - this.mnemonic = mnemonic; - } - - public String getFilename() { - return filename; - } - - public String getMnemonic() { - return mnemonic; - } - - @Override - public String toString() { - return "XdagBip39Wallet{" - + "filename='" - + filename - + '\'' - + ", mnemonic='" - + mnemonic - + '\'' - + '}'; - } -} diff --git a/src/main/java/io/xdag/wallet/Bip44WalletUtils.java b/src/main/java/io/xdag/wallet/Bip44WalletUtils.java deleted file mode 100644 index d8dbc08e..00000000 --- a/src/main/java/io/xdag/wallet/Bip44WalletUtils.java +++ /dev/null @@ -1,80 +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.wallet; - -import io.xdag.crypto.Bip32ECKeyPair; -import io.xdag.crypto.Credentials; -import io.xdag.crypto.MnemonicUtils; -import io.xdag.crypto.SecureRandomUtils; - -import java.io.File; -import java.io.IOException; - -import static io.xdag.crypto.Bip32ECKeyPair.HARDENED_BIT; - -public class Bip44WalletUtils extends WalletUtils { - // https://github.com/satoshilabs/slips/blob/master/slip-0044.md - public static final int XDAG_BIP44_CION_TYPE = 586; - - /** - * Generates a BIP-44 compatible Ethereum wallet on top of BIP-39 generated seed. - * - * @param password Will be used for both wallet encryption and passphrase for BIP-39 seed - * @param destinationDirectory The directory containing the wallet - * @return A BIP-39 compatible Ethereum wallet - * @throws CipherException if the underlying cipher is not available - * @throws IOException if the destination cannot be written to - */ - public static Bip39Wallet generateBip44Wallet(String password, File destinationDirectory) - throws CipherException, IOException { - byte[] initialEntropy = new byte[16]; - SecureRandomUtils.secureRandom().nextBytes(initialEntropy); - - String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); - byte[] seed = MnemonicUtils.generateSeed(mnemonic, null); - - Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); - Bip32ECKeyPair bip44Keypair = generateBip44KeyPair(masterKeypair); - - String walletFile = generateWalletFile(password, bip44Keypair, destinationDirectory, false); - - return new Bip39Wallet(walletFile, mnemonic); - } - - public static Bip32ECKeyPair generateBip44KeyPair(Bip32ECKeyPair master) { - // m/44'/586'/0'/0/0 - // xdag coin type 586 at https://github.com/satoshilabs/slips/blob/master/slip-0044.md - final int[] path = {44 | HARDENED_BIT, XDAG_BIP44_CION_TYPE | HARDENED_BIT, 0 | HARDENED_BIT, 0, 0}; - return Bip32ECKeyPair.deriveKeyPair(master, path); - - } - - public static Credentials loadBip44Credentials(String password, String mnemonic) { - byte[] seed = MnemonicUtils.generateSeed(mnemonic, password); - Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); - Bip32ECKeyPair bip44Keypair = generateBip44KeyPair(masterKeypair); - return Credentials.create(bip44Keypair); - } - -} diff --git a/src/main/java/io/xdag/wallet/Wallet.java b/src/main/java/io/xdag/wallet/Wallet.java index 35d38661..c6fe47d8 100644 --- a/src/main/java/io/xdag/wallet/Wallet.java +++ b/src/main/java/io/xdag/wallet/Wallet.java @@ -23,230 +23,428 @@ */ package io.xdag.wallet; - -import io.xdag.crypto.ECKeyPair; -import io.xdag.crypto.Hash; -import io.xdag.crypto.Keys; -import io.xdag.utils.Numeric; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; -import org.bouncycastle.crypto.generators.SCrypt; -import org.bouncycastle.crypto.params.KeyParameter; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -import java.util.UUID; +import io.xdag.config.Config; +import io.xdag.core.SimpleEncoder; +import io.xdag.crypto.*; +import io.xdag.utils.ByteArrayWrapper; +import io.xdag.utils.SimpleDecoder; +import io.xdag.utils.SystemUtil; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.bouncycastle.crypto.generators.BCrypt; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermission; +import java.util.*; import static java.nio.charset.StandardCharsets.UTF_8; -import static io.xdag.crypto.SecureRandomUtils.secureRandom; +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; +@Slf4j +@Getter +@Setter public class Wallet { - private static final int N_LIGHT = 1 << 12; - private static final int P_LIGHT = 6; + private static final int VERSION = 4; + private static final int SALT_LENGTH = 16; + private static final int BCRYPT_COST = 12; + private static final String MNEMONIC_PASS_PHRASE = ""; - private static final int N_STANDARD = 1 << 18; - private static final int P_STANDARD = 1; + public static final Set POSIX_SECURED_PERMISSIONS = Set.of(OWNER_READ, OWNER_WRITE); - private static final int R = 8; - private static final int DKLEN = 32; + private final File file; + private final Config config; - private static final int CURRENT_VERSION = 3; + private final Map accounts = Collections.synchronizedMap(new LinkedHashMap<>()); + private String password; - private static final String CIPHER = "aes-128-ctr"; - static final String AES_128_CTR = "pbkdf2"; - static final String SCRYPT = "scrypt"; + // hd wallet key + private String mnemonicPhrase = ""; + private int nextAccountIndex = 0; - public static WalletFile create(String password, ECKeyPair ecKeyPair, int n, int p) - throws CipherException { + /** + * Creates a new wallet instance. + */ + public Wallet(Config config) { + this.file = FileUtils.getFile(config.getWalletSpec().getWalletFilePath()); + this.config = config; + } - byte[] salt = generateRandomBytes(32); + /** + * Returns whether the wallet file exists and non-empty. + */ + public boolean exists() { + return file.length() > 0; + } - byte[] derivedKey = - generateDerivedScryptKey(password.getBytes(UTF_8), salt, n, R, p, DKLEN); + /** + * Deletes the wallet file. + */ + public void delete() throws IOException { + Files.delete(file.toPath()); + } - byte[] encryptKey = Arrays.copyOfRange(derivedKey, 0, 16); - byte[] iv = generateRandomBytes(16); + /** + * Returns the file where the wallet is persisted. + */ + public File getFile() { + return file; + } - byte[] privateKeyBytes = - Numeric.toBytesPadded(ecKeyPair.getPrivateKey(), Keys.PRIVATE_KEY_SIZE); + /** + * Locks the wallet. + */ + public void lock() { + password = null; + accounts.clear(); + } - byte[] cipherText = - performCipherOperation(Cipher.ENCRYPT_MODE, iv, encryptKey, privateKeyBytes); + public ECKeyPair getDefKey() { + List accountList = getAccounts(); + if(CollectionUtils.isNotEmpty(accountList)) { + return accountList.get(0); + } + return null; + } - byte[] mac = generateMac(derivedKey, cipherText); + /** + * Unlocks this wallet + */ + public boolean unlock(String password) { + if (password == null) { + throw new IllegalArgumentException("Password can not be null"); + } - return createWalletFile(ecKeyPair, cipherText, iv, salt, mac, n, p); + try { + byte[] key; + byte[] salt; + + if (exists()) { + + SimpleDecoder dec = new SimpleDecoder(FileUtils.readFileToByteArray(file)); + int version = dec.readInt(); // version + + Set newAccounts = null; + switch (version) { + // only version 4 + case 4 -> { + salt = dec.readBytes(); + key = BCrypt.generate(password.getBytes(UTF_8), salt, BCRYPT_COST); + try { + newAccounts = readAccounts(key, dec, true, version); + readHdSeed(key, dec); + } catch (Exception e) { + log.warn("Failed to read HD mnemonic phrase"); + return false; + } + } + default -> throw new RuntimeException("Unknown wallet version."); + } + + synchronized (accounts) { + accounts.clear(); + for (ECKeyPair account : newAccounts) { + ByteArrayWrapper baw = ByteArrayWrapper.of(Keys.toBytesAddress(account)); + accounts.put(baw, account); + } + } + } + this.password = password; + return true; + } catch (Exception e) { + log.error("Failed to open wallet", e); + } + return false; } - public static WalletFile createStandard(String password, ECKeyPair ecKeyPair) - throws CipherException { - return create(password, ecKeyPair, N_STANDARD, P_STANDARD); + /** + * Reads the account keys. + */ + protected LinkedHashSet readAccounts(byte[] key, SimpleDecoder dec, boolean vlq, int version) { + LinkedHashSet keys = new LinkedHashSet<>(); + int total = dec.readInt(); // size + + for (int i = 0; i < total; i++) { + byte[] iv = dec.readBytes(vlq); + byte[] privateKey = Aes.decrypt(dec.readBytes(vlq), key, iv); + keys.add(ECKeyPair.create(privateKey)); + } + return keys; } - public static WalletFile createLight(String password, ECKeyPair ecKeyPair) - throws CipherException { - return create(password, ecKeyPair, N_LIGHT, P_LIGHT); + /** + * Writes the account keys. + */ + protected void writeAccounts(byte[] key, SimpleEncoder enc) { + synchronized (accounts) { + enc.writeInt(accounts.size()); + for (ECKeyPair a : accounts.values()) { + byte[] iv = SecureRandomUtils.secureRandom().generateSeed(16); + + enc.writeBytes(iv); + enc.writeBytes(Aes.encrypt(a.getPrivateKey().toByteArray(), key, iv)); + } + } } - private static WalletFile createWalletFile( - ECKeyPair ecKeyPair, - byte[] cipherText, - byte[] iv, - byte[] salt, - byte[] mac, - int n, - int p) { - - WalletFile walletFile = new WalletFile(); - walletFile.setAddress(Keys.getAddress(ecKeyPair)); + /** + * Reads the mnemonic phase and next account index. + */ + protected void readHdSeed(byte[] key, SimpleDecoder dec) { + byte[] iv = dec.readBytes(); + byte[] hdSeedEncrypted = dec.readBytes(); + byte[] hdSeedRaw = Aes.decrypt(hdSeedEncrypted, key, iv); + + SimpleDecoder d = new SimpleDecoder(hdSeedRaw); + mnemonicPhrase = d.readString(); + nextAccountIndex = d.readInt(); + } - WalletFile.Crypto crypto = new WalletFile.Crypto(); - crypto.setCipher(CIPHER); - crypto.setCiphertext(Numeric.toHexStringNoPrefix(cipherText)); + /** + * Writes the mnemonic phase and next account index. + */ + protected void writeHdSeed(byte[] key, SimpleEncoder enc) { + SimpleEncoder e = new SimpleEncoder(); + e.writeString(mnemonicPhrase); + e.writeInt(nextAccountIndex); - WalletFile.CipherParams cipherParams = new WalletFile.CipherParams(); - cipherParams.setIv(Numeric.toHexStringNoPrefix(iv)); - crypto.setCipherparams(cipherParams); + byte[] iv = SecureRandomUtils.secureRandom().generateSeed(16); + byte[] hdSeedRaw = e.toBytes(); + byte[] hdSeedEncrypted = Aes.encrypt(hdSeedRaw, key, iv); - crypto.setKdf(SCRYPT); - WalletFile.ScryptKdfParams kdfParams = new WalletFile.ScryptKdfParams(); - kdfParams.setDklen(DKLEN); - kdfParams.setN(n); - kdfParams.setP(p); - kdfParams.setR(R); - kdfParams.setSalt(Numeric.toHexStringNoPrefix(salt)); - crypto.setKdfparams(kdfParams); + enc.writeBytes(iv); + enc.writeBytes(hdSeedEncrypted); + } - crypto.setMac(Numeric.toHexStringNoPrefix(mac)); - walletFile.setCrypto(crypto); - walletFile.setId(UUID.randomUUID().toString()); - walletFile.setVersion(CURRENT_VERSION); + /** + * Returns if this wallet is unlocked. + */ + public boolean isUnlocked() { + return !isLocked(); + } - return walletFile; + /** + * Returns whether the wallet is locked. + */ + public boolean isLocked() { + return password == null; } - private static byte[] generateDerivedScryptKey( - byte[] password, byte[] salt, int n, int r, int p, int dkLen) { - return SCrypt.generate(password, salt, n, r, p, dkLen); + /** + * Sets the accounts inside this wallet. + */ + public void setAccounts(List list) { + requireUnlocked(); + accounts.clear(); + for (ECKeyPair key : list) { + addAccount(key); + } } - private static byte[] generateAes128CtrDerivedKey( - byte[] password, byte[] salt, int c, String prf) throws CipherException { + /** + * Returns a copy of the accounts inside this wallet. + */ + public List getAccounts(){ + requireUnlocked(); + synchronized (accounts) { + return new ArrayList<>(accounts.values()); + } + } - if (!prf.equals("hmac-sha256")) { - throw new CipherException("Unsupported prf:" + prf); + /** + * Returns account by index. + */ + public ECKeyPair getAccount(int idx) { + requireUnlocked(); + synchronized (accounts) { + return getAccounts().get(idx); } + } - // Java 8 supports this, but you have to convert the password to a character array, see - // http://stackoverflow.com/a/27928435/3211687 + /** + * Returns account by address. + */ + public ECKeyPair getAccount(byte[] address) { + requireUnlocked(); - PKCS5S2ParametersGenerator gen = new PKCS5S2ParametersGenerator(new SHA256Digest()); - gen.init(password, salt, c); - return ((KeyParameter) gen.generateDerivedParameters(256)).getKey(); + synchronized (accounts) { + return accounts.get(ByteArrayWrapper.of(address)); + } } - private static byte[] performCipherOperation( - int mode, byte[] iv, byte[] encryptKey, byte[] text) throws CipherException { + /** + * Flushes this wallet into the disk. + */ + public boolean flush() { + requireUnlocked(); try { - IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + SimpleEncoder enc = new SimpleEncoder(); + enc.writeInt(VERSION); - SecretKeySpec secretKeySpec = new SecretKeySpec(encryptKey, "AES"); - cipher.init(mode, secretKeySpec, ivParameterSpec); - return cipher.doFinal(text); - } catch (NoSuchPaddingException - | NoSuchAlgorithmException - | InvalidAlgorithmParameterException - | InvalidKeyException - | BadPaddingException - | IllegalBlockSizeException e) { - throw new CipherException("Error performing cipher operation", e); + byte[] salt = SecureRandomUtils.secureRandom().generateSeed(SALT_LENGTH); + enc.writeBytes(salt); + + byte[] key = BCrypt.generate(password.getBytes(UTF_8), salt, BCRYPT_COST); + + writeAccounts(key, enc); + writeHdSeed(key, enc); + + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { + log.error("Failed to create the directory for wallet"); + return false; + } + + // set posix permissions + if (SystemUtil.isPosix() && !file.exists()) { + Files.createFile(file.toPath()); + Files.setPosixFilePermissions(file.toPath(), POSIX_SECURED_PERMISSIONS); + } + + FileUtils.writeByteArrayToFile(file, enc.toBytes()); + return true; + } catch (IOException e) { + log.error("Failed to write wallet to disk", e); } + return false; } - private static byte[] generateMac(byte[] derivedKey, byte[] cipherText) { - byte[] result = new byte[16 + cipherText.length]; - - System.arraycopy(derivedKey, 16, result, 0, 16); - System.arraycopy(cipherText, 0, result, 16, cipherText.length); - return Hash.sha256(result); + private void requireUnlocked() { + if (!isUnlocked()) { + throw new RuntimeException("Wallet is Locked!"); + } } - public static ECKeyPair decrypt(String password, WalletFile walletFile) throws CipherException { + /** + * Adds a new account to the wallet. + */ + public boolean addAccount(ECKeyPair newKey) { + requireUnlocked(); - validate(walletFile); + synchronized (accounts) { + ByteArrayWrapper address = ByteArrayWrapper.of(Keys.toBytesAddress(newKey)); + if (accounts.containsKey(address)) { + return false; + } - WalletFile.Crypto crypto = walletFile.getCrypto(); + accounts.put(address, newKey); + return true; + } + } + + /** + * Add an account with randomly generated key. + */ + public ECKeyPair addAccountRandom() { + ECKeyPair key = Keys.createEcKeyPair(); + addAccount(key); + return key; + } - byte[] mac = Numeric.hexStringToByteArray(crypto.getMac()); - byte[] iv = Numeric.hexStringToByteArray(crypto.getCipherparams().getIv()); - byte[] cipherText = Numeric.hexStringToByteArray(crypto.getCiphertext()); + /** + * Adds a list of accounts to the wallet. + */ + public int addAccounts(List accounts) { + requireUnlocked(); - byte[] derivedKey; + int n = 0; + for (ECKeyPair acc : accounts) { + n += addAccount(acc) ? 1 : 0; + } + return n; + } - WalletFile.KdfParams kdfParams = crypto.getKdfparams(); - if (kdfParams instanceof WalletFile.ScryptKdfParams) { - WalletFile.ScryptKdfParams scryptKdfParams = - (WalletFile.ScryptKdfParams) crypto.getKdfparams(); - int dklen = scryptKdfParams.getDklen(); - int n = scryptKdfParams.getN(); - int p = scryptKdfParams.getP(); - int r = scryptKdfParams.getR(); - byte[] salt = Numeric.hexStringToByteArray(scryptKdfParams.getSalt()); - derivedKey = generateDerivedScryptKey(password.getBytes(UTF_8), salt, n, r, p, dklen); - } else if (kdfParams instanceof WalletFile.Aes128CtrKdfParams) { - WalletFile.Aes128CtrKdfParams aes128CtrKdfParams = - (WalletFile.Aes128CtrKdfParams) crypto.getKdfparams(); - int c = aes128CtrKdfParams.getC(); - String prf = aes128CtrKdfParams.getPrf(); - byte[] salt = Numeric.hexStringToByteArray(aes128CtrKdfParams.getSalt()); + /** + * Deletes an account in the wallet. + */ + public boolean removeAccount(ECKeyPair key) { + return removeAccount(Keys.toBytesAddress(key)); + } - derivedKey = generateAes128CtrDerivedKey(password.getBytes(UTF_8), salt, c, prf); - } else { - throw new CipherException("Unable to deserialize params: " + crypto.getKdf()); + /** + * Deletes an account in the wallet. + */ + public boolean removeAccount(byte[] address) { + requireUnlocked(); + synchronized (accounts) { + return accounts.remove(ByteArrayWrapper.of(address)) != null; } + } - byte[] derivedMac = generateMac(derivedKey, cipherText); + /** + * Changes the password of the wallet. + */ + public void changePassword(String newPassword) { + requireUnlocked(); - if (!Arrays.equals(derivedMac, mac)) { - throw new CipherException("Invalid password provided"); + if (newPassword == null) { + throw new IllegalArgumentException("Password can not be null"); } - byte[] encryptKey = Arrays.copyOfRange(derivedKey, 0, 16); - byte[] privateKey = performCipherOperation(Cipher.DECRYPT_MODE, iv, encryptKey, cipherText); - return ECKeyPair.create(privateKey); + this.password = newPassword; } - static void validate(WalletFile walletFile) throws CipherException { - WalletFile.Crypto crypto = walletFile.getCrypto(); + // ================ + // HD wallet + // ================ + + /** + * Returns whether the HD seed is initialized. + * + * @return true if set, otherwise false + */ + public boolean isHdWalletInitialized() { + requireUnlocked(); + return mnemonicPhrase != null && !mnemonicPhrase.isEmpty(); + } - if (walletFile.getVersion() != CURRENT_VERSION) { - throw new CipherException("Wallet version is not supported"); - } + /** + * Initialize the HD wallet. + * + * @param mnemonicPhrase + * the mnemonic word list + */ + public void initializeHdWallet(String mnemonicPhrase) { + this.mnemonicPhrase = mnemonicPhrase; + this.nextAccountIndex = 0; + } - if (!crypto.getCipher().equals(CIPHER)) { - throw new CipherException("Wallet cipher is not supported"); - } + /** + * Returns the HD seed. + */ + public byte[] getSeed() { + return MnemonicUtils.generateSeed(this.mnemonicPhrase, MNEMONIC_PASS_PHRASE); + } - if (!crypto.getKdf().equals(AES_128_CTR) && !crypto.getKdf().equals(SCRYPT)) { - throw new CipherException("KDF type is not supported"); + /** + * Derives a key based on the current HD account index, and put it into the + * wallet. + */ + public ECKeyPair addAccountWithNextHdKey() { + requireUnlocked(); + requireHdWalletInitialized(); + + synchronized (accounts) { + byte[] seed = getSeed(); + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + Bip32ECKeyPair bip44Keypair = WalletUtils.generateBip44KeyPair(masterKeypair, nextAccountIndex++); + ByteArrayWrapper address = ByteArrayWrapper.of(Keys.toBytesAddress(bip44Keypair)); + accounts.put(address, bip44Keypair); + return bip44Keypair; } } - static byte[] generateRandomBytes(int size) { - byte[] bytes = new byte[size]; - secureRandom().nextBytes(bytes); - return bytes; + private void requireHdWalletInitialized() { + if (!isHdWalletInitialized()) { + throw new IllegalArgumentException("HD Seed is not initialized"); + } } + } diff --git a/src/main/java/io/xdag/wallet/WalletFile.java b/src/main/java/io/xdag/wallet/WalletFile.java deleted file mode 100644 index aa56e578..00000000 --- a/src/main/java/io/xdag/wallet/WalletFile.java +++ /dev/null @@ -1,467 +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.wallet; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.JsonSubTypes; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import java.io.IOException; - -public class WalletFile { - - private String address; - private Crypto crypto; - private String id; - private int version; - - public WalletFile() {} - - public String getAddress() { - return address; - } - - public void setAddress(String address) { - this.address = address; - } - - public Crypto getCrypto() { - return crypto; - } - - @JsonSetter("crypto") - public void setCrypto(Crypto crypto) { - this.crypto = crypto; - } - - @JsonSetter("Crypto") // older wallet files may have this attribute name - public void setCryptoV1(Crypto crypto) { - setCrypto(crypto); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public int getVersion() { - return version; - } - - public void setVersion(int version) { - this.version = version; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof WalletFile)) { - return false; - } - - WalletFile that = (WalletFile) o; - - if (getAddress() != null - ? !getAddress().equals(that.getAddress()) - : that.getAddress() != null) { - return false; - } - if (getCrypto() != null - ? !getCrypto().equals(that.getCrypto()) - : that.getCrypto() != null) { - return false; - } - if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) { - return false; - } - return version == that.version; - } - - @Override - public int hashCode() { - int result = getAddress() != null ? getAddress().hashCode() : 0; - result = 31 * result + (getCrypto() != null ? getCrypto().hashCode() : 0); - result = 31 * result + (getId() != null ? getId().hashCode() : 0); - result = 31 * result + version; - return result; - } - - public static class Crypto { - private String cipher; - private String ciphertext; - private CipherParams cipherparams; - - private String kdf; - private KdfParams kdfparams; - - private String mac; - - public Crypto() {} - - public String getCipher() { - return cipher; - } - - public void setCipher(String cipher) { - this.cipher = cipher; - } - - public String getCiphertext() { - return ciphertext; - } - - public void setCiphertext(String ciphertext) { - this.ciphertext = ciphertext; - } - - public CipherParams getCipherparams() { - return cipherparams; - } - - public void setCipherparams(CipherParams cipherparams) { - this.cipherparams = cipherparams; - } - - public String getKdf() { - return kdf; - } - - public void setKdf(String kdf) { - this.kdf = kdf; - } - - public KdfParams getKdfparams() { - return kdfparams; - } - - @JsonTypeInfo( - use = JsonTypeInfo.Id.NAME, - include = JsonTypeInfo.As.EXTERNAL_PROPERTY, - property = "kdf") - @JsonSubTypes({ - @JsonSubTypes.Type(value = Aes128CtrKdfParams.class, name = Wallet.AES_128_CTR), - @JsonSubTypes.Type(value = ScryptKdfParams.class, name = Wallet.SCRYPT) - }) - // To support my Ether Wallet keys uncomment this annotation & comment out the above - // @JsonDeserialize(using = KdfParamsDeserialiser.class) - // Also add the following to the ObjectMapperFactory - // objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true); - public void setKdfparams(KdfParams kdfparams) { - this.kdfparams = kdfparams; - } - - public String getMac() { - return mac; - } - - public void setMac(String mac) { - this.mac = mac; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Crypto)) { - return false; - } - - Crypto that = (Crypto) o; - - if (getCipher() != null - ? !getCipher().equals(that.getCipher()) - : that.getCipher() != null) { - return false; - } - if (getCiphertext() != null - ? !getCiphertext().equals(that.getCiphertext()) - : that.getCiphertext() != null) { - return false; - } - if (getCipherparams() != null - ? !getCipherparams().equals(that.getCipherparams()) - : that.getCipherparams() != null) { - return false; - } - if (getKdf() != null ? !getKdf().equals(that.getKdf()) : that.getKdf() != null) { - return false; - } - if (getKdfparams() != null - ? !getKdfparams().equals(that.getKdfparams()) - : that.getKdfparams() != null) { - return false; - } - return getMac() != null ? getMac().equals(that.getMac()) : that.getMac() == null; - } - - @Override - public int hashCode() { - int result = getCipher() != null ? getCipher().hashCode() : 0; - result = 31 * result + (getCiphertext() != null ? getCiphertext().hashCode() : 0); - result = 31 * result + (getCipherparams() != null ? getCipherparams().hashCode() : 0); - result = 31 * result + (getKdf() != null ? getKdf().hashCode() : 0); - result = 31 * result + (getKdfparams() != null ? getKdfparams().hashCode() : 0); - result = 31 * result + (getMac() != null ? getMac().hashCode() : 0); - return result; - } - } - - public static class CipherParams { - private String iv; - - public CipherParams() {} - - public String getIv() { - return iv; - } - - public void setIv(String iv) { - this.iv = iv; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof CipherParams)) { - return false; - } - - CipherParams that = (CipherParams) o; - - return getIv() != null ? getIv().equals(that.getIv()) : that.getIv() == null; - } - - @Override - public int hashCode() { - int result = getIv() != null ? getIv().hashCode() : 0; - return result; - } - } - - interface KdfParams { - int getDklen(); - - String getSalt(); - } - - public static class Aes128CtrKdfParams implements KdfParams { - private int dklen; - private int c; - private String prf; - private String salt; - - public Aes128CtrKdfParams() {} - - public int getDklen() { - return dklen; - } - - public void setDklen(int dklen) { - this.dklen = dklen; - } - - public int getC() { - return c; - } - - public void setC(int c) { - this.c = c; - } - - public String getPrf() { - return prf; - } - - public void setPrf(String prf) { - this.prf = prf; - } - - public String getSalt() { - return salt; - } - - public void setSalt(String salt) { - this.salt = salt; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Aes128CtrKdfParams)) { - return false; - } - - Aes128CtrKdfParams that = (Aes128CtrKdfParams) o; - - if (dklen != that.dklen) { - return false; - } - if (c != that.c) { - return false; - } - if (getPrf() != null ? !getPrf().equals(that.getPrf()) : that.getPrf() != null) { - return false; - } - return getSalt() != null ? getSalt().equals(that.getSalt()) : that.getSalt() == null; - } - - @Override - public int hashCode() { - int result = dklen; - result = 31 * result + c; - result = 31 * result + (getPrf() != null ? getPrf().hashCode() : 0); - result = 31 * result + (getSalt() != null ? getSalt().hashCode() : 0); - return result; - } - } - - public static class ScryptKdfParams implements KdfParams { - private int dklen; - private int n; - private int p; - private int r; - private String salt; - - public ScryptKdfParams() {} - - public int getDklen() { - return dklen; - } - - public void setDklen(int dklen) { - this.dklen = dklen; - } - - public int getN() { - return n; - } - - public void setN(int n) { - this.n = n; - } - - public int getP() { - return p; - } - - public void setP(int p) { - this.p = p; - } - - public int getR() { - return r; - } - - public void setR(int r) { - this.r = r; - } - - public String getSalt() { - return salt; - } - - public void setSalt(String salt) { - this.salt = salt; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof ScryptKdfParams)) { - return false; - } - - ScryptKdfParams that = (ScryptKdfParams) o; - - if (dklen != that.dklen) { - return false; - } - if (n != that.n) { - return false; - } - if (p != that.p) { - return false; - } - if (r != that.r) { - return false; - } - return getSalt() != null ? getSalt().equals(that.getSalt()) : that.getSalt() == null; - } - - @Override - public int hashCode() { - int result = dklen; - result = 31 * result + n; - result = 31 * result + p; - result = 31 * result + r; - result = 31 * result + (getSalt() != null ? getSalt().hashCode() : 0); - return result; - } - } - - // If we need to work with MyEtherWallet we'll need to use this deserializer, see the - // following issue https://github.com/kvhnuke/etherwallet/issues/269 - static class KdfParamsDeserialiser extends JsonDeserializer { - - @Override - public KdfParams deserialize( - JsonParser jsonParser, DeserializationContext deserializationContext) - throws IOException { - - ObjectMapper objectMapper = (ObjectMapper) jsonParser.getCodec(); - ObjectNode root = objectMapper.readTree(jsonParser); - KdfParams kdfParams; - - // it would be preferable to detect the class to use based on the kdf parameter in the - // container object instance - JsonNode n = root.get("n"); - if (n == null) { - kdfParams = objectMapper.convertValue(root, Aes128CtrKdfParams.class); - } else { - kdfParams = objectMapper.convertValue(root, ScryptKdfParams.class); - } - - return kdfParams; - } - } - -} diff --git a/src/main/java/io/xdag/wallet/WalletManager.java b/src/main/java/io/xdag/wallet/WalletManager.java deleted file mode 100644 index b70efce1..00000000 --- a/src/main/java/io/xdag/wallet/WalletManager.java +++ /dev/null @@ -1,73 +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.wallet; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.xdag.crypto.*; - -import java.io.File; -import java.io.IOException; -import java.util.Optional; - -/** - * Wallet Manager - */ -public class WalletManager { - - /** - * Create BIP44 Xdag Wallet - * - * @param password User Password - * @param destinationDirectory Keystore Directory - */ - public static Optional createBip44Wallet(String password, File destinationDirectory) throws CipherException, IOException { - Bip39Wallet wallet = Bip44WalletUtils.generateBip44Wallet(password, destinationDirectory); - Credentials credentials = Bip44WalletUtils.loadBip44Credentials(password, wallet.getMnemonic()); - return Optional.of(credentials); - } - - /** - * Import BIP44 Wallet From Mnemonic - * - * @param password User Password - * @param mnemonic Mnemonic of 12 Worlds - */ - public static Optional importBip44WalletFromMnemonic(String password, String mnemonic) { - return Optional.of(Bip44WalletUtils.loadBip44Credentials(password, mnemonic)); - } - - /** - * Import BIP44 Wallet From Keystore - * - * @param password User Password - * @param keystore Keystore String - */ - public static Optional importBip44WalletFromKeystore(String password, String keystore) throws JsonProcessingException, CipherException { - ObjectMapper objectMapper = new ObjectMapper(); - WalletFile walletFile = objectMapper.readValue(keystore, WalletFile.class); - ECKeyPair ecKeyPair = Wallet.decrypt(password, walletFile); - return Optional.of(Credentials.create(ecKeyPair)); - } -} diff --git a/src/main/java/io/xdag/wallet/WalletUtils.java b/src/main/java/io/xdag/wallet/WalletUtils.java index a52b2278..53de60fd 100644 --- a/src/main/java/io/xdag/wallet/WalletUtils.java +++ b/src/main/java/io/xdag/wallet/WalletUtils.java @@ -23,213 +23,30 @@ */ package io.xdag.wallet; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.xdag.crypto.*; -import io.xdag.utils.Numeric; +import io.xdag.crypto.Bip32ECKeyPair; +import io.xdag.crypto.MnemonicUtils; +import lombok.extern.slf4j.Slf4j; -import java.io.File; -import java.io.IOException; -import java.security.SecureRandom; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; +import static io.xdag.crypto.Bip32ECKeyPair.HARDENED_BIT; -import static io.xdag.crypto.Hash.sha256; -import static io.xdag.crypto.Keys.ADDRESS_LENGTH_IN_HEX; -import static io.xdag.crypto.Keys.PRIVATE_KEY_LENGTH_IN_HEX; - -/** Utility functions for working with Wallet files. */ +@Slf4j public class WalletUtils { - private static final ObjectMapper objectMapper = new ObjectMapper(); - private static final SecureRandom secureRandom = SecureRandomUtils.secureRandom(); - - static { - objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } - - public static String generateFullNewWalletFile(String password, File destinationDirectory) - throws CipherException, IOException { - - return generateNewWalletFile(password, destinationDirectory, true); - } - - public static String generateLightNewWalletFile(String password, File destinationDirectory) - throws CipherException, IOException { - - return generateNewWalletFile(password, destinationDirectory, false); - } - - public static String generateNewWalletFile(String password, File destinationDirectory) - throws CipherException, IOException { - return generateFullNewWalletFile(password, destinationDirectory); - } - - public static String generateNewWalletFile( - String password, File destinationDirectory, boolean useFullScrypt) - throws CipherException, IOException { - - ECKeyPair ecKeyPair = Keys.createEcKeyPair(); - return generateWalletFile(password, ecKeyPair, destinationDirectory, useFullScrypt); - } - - public static String generateWalletFile( - String password, ECKeyPair ecKeyPair, File destinationDirectory, boolean useFullScrypt) - throws CipherException, IOException { - - WalletFile walletFile; - if (useFullScrypt) { - walletFile = Wallet.createStandard(password, ecKeyPair); - } else { - walletFile = Wallet.createLight(password, ecKeyPair); - } - - String fileName = getWalletFileName(walletFile); - File destination = new File(destinationDirectory, fileName); - - objectMapper.writeValue(destination, walletFile); - - return fileName; - } - - /** - * Generates a BIP-39 compatible Xdag wallet. The private key for the wallet can be - * calculated using following algorithm: - * - *
-     *     Key = SHA-256(BIP_39_SEED(mnemonic, password))
-     * 
- * - * @param password Will be used for both wallet encryption and passphrase for BIP-39 seed - * @param destinationDirectory The directory containing the wallet - * @return A BIP-39 compatible Xdag wallet - * @throws CipherException if the underlying cipher is not available - * @throws IOException if the destination cannot be written to - */ - public static Bip39Wallet generateBip39Wallet(String password, File destinationDirectory) - throws CipherException, IOException { - byte[] initialEntropy = new byte[16]; - secureRandom.nextBytes(initialEntropy); + // https://github.com/satoshilabs/slips/blob/master/slip-0044.md + public static final int XDAG_BIP44_CION_TYPE = 586; - String mnemonic = MnemonicUtils.generateMnemonic(initialEntropy); - byte[] seed = MnemonicUtils.generateSeed(mnemonic, password); - ECKeyPair privateKey = ECKeyPair.create(sha256(seed)); - - String walletFile = generateWalletFile(password, privateKey, destinationDirectory, false); - - return new Bip39Wallet(walletFile, mnemonic); + public static Bip32ECKeyPair generateBip44KeyPair(Bip32ECKeyPair master, int index) { + // m/44'/586'/0'/0/0 + // xdag coin type 586 at https://github.com/satoshilabs/slips/blob/master/slip-0044.md + final int[] path = {44 | HARDENED_BIT, XDAG_BIP44_CION_TYPE | HARDENED_BIT, 0 | HARDENED_BIT, 0, index}; + return Bip32ECKeyPair.deriveKeyPair(master, path); } - /** - * Generates a BIP-39 compatible Xdag wallet using a mnemonic passed as argument. - * - * @param password Will be used for both wallet encryption and passphrase for BIP-39 seed - * @param mnemonic The mnemonic that will be used to generate the seed - * @param destinationDirectory The directory containing the wallet - * @return A BIP-39 compatible Xdag wallet - * @throws CipherException if the underlying cipher is not available - * @throws IOException if the destination cannot be written to - */ - public static Bip39Wallet generateBip39WalletFromMnemonic( - String password, String mnemonic, File destinationDirectory) - throws CipherException, IOException { + public static Bip32ECKeyPair importMnemonic(Wallet wallet, String password, String mnemonic, int index) { + wallet.unlock(password); byte[] seed = MnemonicUtils.generateSeed(mnemonic, password); - ECKeyPair privateKey = ECKeyPair.create(sha256(seed)); - - String walletFile = generateWalletFile(password, privateKey, destinationDirectory, false); - - return new Bip39Wallet(walletFile, mnemonic); - } - - public static Credentials loadCredentials(String password, String source) - throws IOException, CipherException { - return loadCredentials(password, new File(source)); + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + return generateBip44KeyPair(masterKeypair, index); } - public static Credentials loadCredentials(String password, File source) - throws IOException, CipherException { - WalletFile walletFile = objectMapper.readValue(source, WalletFile.class); - return Credentials.create(Wallet.decrypt(password, walletFile)); - } - - public static Credentials loadBip39Credentials(String password, String mnemonic) { - byte[] seed = MnemonicUtils.generateSeed(mnemonic, password); - return Credentials.create(ECKeyPair.create(sha256(seed))); - } - - /** - * Load credentials from JSON wallet string. - * - * @param password - password to decrypt JSON wallet string - * @param content - JSON wallet content string - * @return Xdag credentials - * @throws CipherException if the underlying cipher is not available - * @throws IOException if a low-level I/O problem (unexpected end-of-input, network error) - * occurs - */ - public static Credentials loadJsonCredentials(String password, String content) - throws IOException, CipherException { - WalletFile walletFile = objectMapper.readValue(content, WalletFile.class); - return Credentials.create(Wallet.decrypt(password, walletFile)); - } - - private static String getWalletFileName(WalletFile walletFile) { - DateTimeFormatter format = - DateTimeFormatter.ofPattern("'UTC--'yyyy-MM-dd'T'HH-mm-ss.nVV'--'"); - ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC); - - return now.format(format) + walletFile.getAddress() + ".json"; - } - - public static String getDefaultKeyDirectory() { - return getDefaultKeyDirectory(System.getProperty("os.name")); - } - - static String getDefaultKeyDirectory(String osName1) { - String osName = osName1.toLowerCase(); - - if (osName.startsWith("mac")) { - return String.format( - "%s%sLibrary%sXdag", - System.getProperty("user.home"), File.separator, File.separator); - } else if (osName.startsWith("win")) { - return String.format("%s%sXdag", System.getenv("APPDATA"), File.separator); - } else { - return String.format("%s%s.xdag", System.getProperty("user.home"), File.separator); - } - } - - public static String getTestnetKeyDirectory() { - return String.format( - "%s%stestnet%skeystore", getDefaultKeyDirectory(), File.separator, File.separator); - } - - public static String getMainnetKeyDirectory() { - return String.format("%s%skeystore", getDefaultKeyDirectory(), File.separator); - } - - public static boolean isValidPrivateKey(String privateKey) { - String cleanPrivateKey = Numeric.cleanHexPrefix(privateKey); - return cleanPrivateKey.length() == PRIVATE_KEY_LENGTH_IN_HEX; - } - - public static boolean isValidAddress(String input) { - return isValidAddress(input, ADDRESS_LENGTH_IN_HEX); - } - - public static boolean isValidAddress(String input, int addressLength) { - String cleanInput = Numeric.cleanHexPrefix(input); - - try { - Numeric.toBigIntNoPrefix(cleanInput); - } catch (NumberFormatException e) { - return false; - } - - return cleanInput.length() == addressLength; - } } - diff --git a/src/test/java/io/xdag/cli/XdagCliTest.java b/src/test/java/io/xdag/cli/XdagCliTest.java new file mode 100644 index 00000000..0cb6ef24 --- /dev/null +++ b/src/test/java/io/xdag/cli/XdagCliTest.java @@ -0,0 +1,464 @@ +/* + * 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.cli; + +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; +import io.xdag.config.MainnetConfig; +import io.xdag.config.TestnetConfig; +import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.Keys; +import io.xdag.utils.BytesUtils; +import io.xdag.wallet.Wallet; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.ExpectedSystemExit; +import org.mockito.Mockito; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.*; + +public class XdagCliTest { + private Config config; + + @Rule + public final ExpectedSystemExit exit = ExpectedSystemExit.none(); + + @Before + public void setUp() throws Exception { + config = new DevnetConfig(); + } + + @Test + public void testMain() throws Exception { + String[] args = { "arg1", "arg2" }; + XdagCli cli = mock(XdagCli.class); + XdagCli.main(args, cli); + verify(cli).start(args); + } + + @Test + public void testHelp() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.start(new String[] { "--help" }); + verify(xdagCLI).printHelp(); + } + + @Test + public void testVersion() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.start(new String[] { "--version" }); + verify(xdagCLI).printVersion(); + } + + @Test + public void testMainnet() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + + // mock accounts + List accounts = new ArrayList<>(); + ECKeyPair account = Keys.createEcKeyPair(); + accounts.add(account); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(wallet.getAccounts()).thenReturn(accounts); + when(wallet.exists()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + xdagCLI.start(new String[] {""}); + assertTrue(xdagCLI.getConfig() instanceof MainnetConfig); + } + + @Test + public void testTestnet() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + + // mock accounts + List accounts = new ArrayList<>(); + ECKeyPair account = Keys.createEcKeyPair(); + accounts.add(account); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(wallet.getAccounts()).thenReturn(accounts); + when(wallet.exists()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + xdagCLI.start(new String[] {"-t"}); + assertTrue(xdagCLI.getConfig() instanceof TestnetConfig); + } + + @Test + public void testLoadAndUnlockWalletWithWrongPassword() { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock(any())).thenReturn(false); + when(xdagCLI.loadWallet()).thenReturn(wallet); + + // mock password + when(xdagCLI.getPassword()).thenReturn("password"); + + } + + @Test + public void testStartKernelWithEmptyWallet() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.exists()).thenReturn(false); + when(wallet.unlock("oldpassword")).thenReturn(true); + doReturn(new ArrayList(), // returns empty wallet + Collections.singletonList(Keys.createEcKeyPair()) // returns wallet with a newly created account + ).when(wallet).getAccounts(); + when(wallet.addAccount(any(ECKeyPair.class))).thenReturn(true); + when(wallet.flush()).thenReturn(true); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock CLI + when(xdagCLI.loadWallet()).thenReturn(wallet); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // mock new account + ECKeyPair newAccount = Keys.createEcKeyPair(); + when(wallet.addAccountRandom()).thenReturn(newAccount); + when(wallet.addAccountWithNextHdKey()).thenReturn(newAccount); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readNewPassword(any(), any()); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.start(); + + // verifies that a new account is added the empty wallet + verify(wallet).unlock("oldpassword"); + verify(wallet, times(1)).getAccounts(); + verify(wallet).addAccountWithNextHdKey(); + + verify(wallet, atLeastOnce()).flush(); + + // verifies that kernel starts + verify(xdagCLI).startKernel(any(), any()); + } + + @Test + public void testStartKernelWithEmptyWalletInvalidNewPassword() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.exists()).thenReturn(false); + + // mock CLI + when(xdagCLI.loadWallet()).thenReturn(wallet); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // mock password + doReturn("a").doReturn("b").when(xdagCLI).readPassword(any()); + + // mock exits + doNothing().when(xdagCLI).exit(anyInt()); + + exit.expectSystemExitWithStatus(-1); + // execution + xdagCLI.start(); + } + + @Test + public void testAccountInit() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + Mockito.doNothing().when(xdagCLI).initHDAccount(); + xdagCLI.start(new String[] { "--account", "init" }); + verify(xdagCLI).initHDAccount(); + } + + @Test + public void testAccountCreate() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + Mockito.doNothing().when(xdagCLI).createAccount(); + xdagCLI.start(new String[] { "--account", "create" }); + verify(xdagCLI).createAccount(); + } + + @Test + public void testAccountList() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + Mockito.doNothing().when(xdagCLI).listAccounts(); + xdagCLI.start(new String[] { "--account", "list" }); + verify(xdagCLI).listAccounts(); + } + + @Test + public void testCreateAccount() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(wallet.isHdWalletInitialized()).thenReturn(true); + when(wallet.addAccount(any(ECKeyPair.class))).thenReturn(true); + when(wallet.flush()).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + + // mock account + ECKeyPair newAccount = Keys.createEcKeyPair(); + when(wallet.addAccountRandom()).thenReturn(newAccount); + when(wallet.addAccountWithNextHdKey()).thenReturn(newAccount); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.createAccount(); + + // verification + verify(wallet).addAccountWithNextHdKey(); + + verify(wallet).flush(); + } + + @Test + public void testListAccounts() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock accounts + List accounts = new ArrayList<>(); + ECKeyPair account = Keys.createEcKeyPair(); + accounts.add(account); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(wallet.getAccounts()).thenReturn(accounts); + when(xdagCLI.loadWallet()).thenReturn(wallet); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.listAccounts(); + + // verification + verify(wallet).getAccounts(); + } + + @Test + public void testChangePasswordIncorrectConfirmation() { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(wallet.flush()).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("a").doReturn("b").when(xdagCLI).readPassword(any()); + doNothing().when(xdagCLI).exit(anyInt()); + + // execution + xdagCLI.changePassword(); + } + + @Test + public void testDumpPrivateKey() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock account + ECKeyPair account = spy(Keys.createEcKeyPair()); + String address = BytesUtils.toHexString(Keys.toBytesAddress(account)); + byte[] addressBytes = Keys.toBytesAddress(account); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.getAccount(addressBytes)).thenReturn(account); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.dumpPrivateKey(address); + + // verification + verify(wallet).getAccount(addressBytes); + verify(account).getPrivateKey(); + } + + @Test + public void testDumpPrivateKeyNotFound() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + // mock address + String address = "c583b6ad1d1cccfc00ae9113db6408f022822b20"; + + byte[] addressBytes = BytesUtils.hexStringToBytes(address); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.getAccount(addressBytes)).thenReturn(null); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.dumpPrivateKey(address); + } + + @Test + public void testImportPrivateKeyExisted() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock private key + ECKeyPair keypair = Keys.createEcKeyPair(); + String key = BytesUtils.toHexString(Keys.toBytesAddress(keypair)); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.addAccount(any(ECKeyPair.class))).thenReturn(false); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.importPrivateKey(key); + } + + @Test + public void testImportPrivateKeyFailedToFlushWalletFile() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock private key + ECKeyPair keypair = Keys.createEcKeyPair(); + String key = BytesUtils.toHexString(Keys.toBytesAddress(keypair)); + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.addAccount(any(ECKeyPair.class))).thenReturn(true); + when(wallet.flush()).thenReturn(false); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.importPrivateKey(key); + } + + @Test + public void testImportPrivateKey() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock private key + final String key = "302e020100300506032b657004220420bd2f24b259aac4bfce3792c31d0f62a7f28b439c3e4feb97050efe5fe254f2af"; + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.addAccount(any(ECKeyPair.class))).thenReturn(true); + when(wallet.flush()).thenReturn(true); + when(wallet.isHdWalletInitialized()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + xdagCLI.importPrivateKey(key); + } + + @Test + public void testImportMnemonic() throws Exception { + XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(config); + + // mock private key + final String errorMnemonic = "aaa bbb ccc"; + final String rightMnemonic = "view cycle bag maple hill famous black doll episode fine congress april"; + + // mock wallet + Wallet wallet = mock(Wallet.class); + when(wallet.unlock("oldpassword")).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); + when(wallet.flush()).thenReturn(true); + + // mock passwords + doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn(null).when(xdagCLI).startKernel(any(), any()); + + // execution + assertFalse(xdagCLI.importMnemonic(errorMnemonic)); + assertTrue(xdagCLI.importMnemonic(rightMnemonic)); + } + +} \ No newline at end of file diff --git a/src/test/java/io/xdag/config/DevnetConfigTest.java b/src/test/java/io/xdag/config/DevnetConfigTest.java index 0270573d..27941e53 100644 --- a/src/test/java/io/xdag/config/DevnetConfigTest.java +++ b/src/test/java/io/xdag/config/DevnetConfigTest.java @@ -1,3 +1,26 @@ +/* + * 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.config; import org.apache.commons.lang3.StringUtils; diff --git a/src/test/java/io/xdag/config/MainnetConfigTest.java b/src/test/java/io/xdag/config/MainnetConfigTest.java index 1ce60a04..6a64c576 100644 --- a/src/test/java/io/xdag/config/MainnetConfigTest.java +++ b/src/test/java/io/xdag/config/MainnetConfigTest.java @@ -1,3 +1,26 @@ +/* + * 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.config; import org.junit.Before; diff --git a/src/test/java/io/xdag/config/TestnetConfigTest.java b/src/test/java/io/xdag/config/TestnetConfigTest.java index 8577804d..bb14a6fd 100644 --- a/src/test/java/io/xdag/config/TestnetConfigTest.java +++ b/src/test/java/io/xdag/config/TestnetConfigTest.java @@ -1,3 +1,26 @@ +/* + * 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.config; import org.junit.Before; diff --git a/src/test/java/io/xdag/core/BlockchainTest.java b/src/test/java/io/xdag/core/BlockchainTest.java index a21dd1a2..b7b0a6da 100644 --- a/src/test/java/io/xdag/core/BlockchainTest.java +++ b/src/test/java/io/xdag/core/BlockchainTest.java @@ -26,10 +26,10 @@ import com.google.common.collect.Lists; import io.xdag.Kernel; import io.xdag.config.Config; -import io.xdag.config.Constants; import io.xdag.config.DevnetConfig; import io.xdag.crypto.ECKeyPair; import io.xdag.crypto.Keys; +import io.xdag.crypto.SampleKeys; import io.xdag.crypto.jni.Native; import io.xdag.db.DatabaseFactory; import io.xdag.db.DatabaseName; @@ -38,8 +38,9 @@ import io.xdag.db.store.OrphanPool; import io.xdag.utils.BasicUtils; import io.xdag.utils.BytesUtils; +import io.xdag.utils.Numeric; import io.xdag.utils.XdagTime; -import io.xdag.wallet.OldWallet; +import io.xdag.wallet.Wallet; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; import org.junit.After; @@ -48,6 +49,7 @@ import org.junit.Test; import org.junit.rules.TemporaryFolder; +import java.io.IOException; import java.math.BigInteger; import java.text.ParseException; import java.util.*; @@ -66,7 +68,8 @@ public class BlockchainTest { public TemporaryFolder root = new TemporaryFolder(); Config config = new DevnetConfig(); - OldWallet xdagWallet; + Wallet wallet; + String pwd; Kernel kernel; DatabaseFactory dbFactory; @@ -82,8 +85,12 @@ public void setUp() throws Exception { if (Native.dnet_crypt_init() < 0) { throw new Exception("dnet crypt init failed"); } - xdagWallet = new OldWallet(); - xdagWallet.init(config); + pwd = "password"; + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); kernel = new Kernel(config); dbFactory = new RocksdbFactory(config); @@ -99,11 +106,12 @@ public void setUp() throws Exception { kernel.setBlockStore(blockStore); kernel.setOrphanPool(orphanPool); - kernel.setWallet(xdagWallet); + kernel.setWallet(wallet); } @After - public void tearDown() throws Exception { + public void tearDown() throws IOException { + wallet.delete(); } private static void assertChainStatus(long nblocks, long nmain, long nextra, long norphan, BlockchainImpl bci) { @@ -482,10 +490,6 @@ public void testOriginFork() throws ParseException { } assertEquals(secondDiff, blockchain.getXdagTopStatus().getTopDiff().toString(16)); - - } - - } diff --git a/src/test/java/io/xdag/core/ExtraBlockTest.java b/src/test/java/io/xdag/core/ExtraBlockTest.java index b6c1afa6..e6e27051 100644 --- a/src/test/java/io/xdag/core/ExtraBlockTest.java +++ b/src/test/java/io/xdag/core/ExtraBlockTest.java @@ -28,22 +28,27 @@ import io.xdag.config.Config; import io.xdag.config.DevnetConfig; import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.SampleKeys; import io.xdag.crypto.jni.Native; import io.xdag.db.DatabaseFactory; import io.xdag.db.DatabaseName; import io.xdag.db.rocksdb.RocksdbFactory; import io.xdag.db.store.BlockStore; import io.xdag.db.store.OrphanPool; +import io.xdag.utils.Numeric; import io.xdag.utils.XdagTime; -import io.xdag.wallet.OldWallet; +import io.xdag.wallet.Wallet; import org.apache.commons.lang3.time.FastDateFormat; +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.text.ParseException; +import java.util.Collections; import java.util.List; import static io.xdag.BlockBuilder.*; @@ -62,7 +67,8 @@ public class ExtraBlockTest { public static FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); Config config = new DevnetConfig(); - OldWallet xdagWallet; + Wallet wallet; + String pwd; Kernel kernel; DatabaseFactory dbFactory; @@ -80,8 +86,13 @@ public void setUp() throws Exception { if (Native.dnet_crypt_init() < 0) { throw new Exception("dnet crypt init failed"); } - xdagWallet = new OldWallet(); - xdagWallet.init(config); + pwd = "password"; + Config config = new DevnetConfig(); + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); kernel = new Kernel(config); dbFactory = new RocksdbFactory(config); @@ -97,7 +108,7 @@ public void setUp() throws Exception { kernel.setBlockStore(blockStore); kernel.setOrphanPool(orphanPool); - kernel.setWallet(xdagWallet); + kernel.setWallet(wallet); } @@ -170,4 +181,9 @@ public void testExtraBlockReUse() throws ParseException { assertEquals(expectedExtraBlocks+1,blockchain.getXdagStats().nextra); } + + @After + public void tearDown() throws IOException { + wallet.delete(); + } } diff --git a/src/test/java/io/xdag/core/RandomXSyncTest.java b/src/test/java/io/xdag/core/RandomXSyncTest.java index 11d40a6f..99f5cdb5 100644 --- a/src/test/java/io/xdag/core/RandomXSyncTest.java +++ b/src/test/java/io/xdag/core/RandomXSyncTest.java @@ -29,6 +29,7 @@ import io.xdag.config.DevnetConfig; import io.xdag.config.RandomXConstants; import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.SampleKeys; import io.xdag.crypto.jni.Native; import io.xdag.db.DatabaseFactory; import io.xdag.db.DatabaseName; @@ -36,8 +37,9 @@ import io.xdag.db.store.BlockStore; import io.xdag.db.store.OrphanPool; import io.xdag.randomx.RandomX; +import io.xdag.utils.Numeric; import io.xdag.utils.XdagTime; -import io.xdag.wallet.OldWallet; +import io.xdag.wallet.Wallet; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.time.FastDateFormat; import org.junit.Before; @@ -47,6 +49,7 @@ import java.math.BigInteger; import java.text.ParseException; +import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -232,9 +235,11 @@ public Kernel createKernel(TemporaryFolder root) throws Exception { if (Native.dnet_crypt_init() < 0) { throw new Exception("dnet crypt init failed"); } - OldWallet xdagWallet = new OldWallet(); - xdagWallet.init(config); - xdagWallet.createNewKey(); + String pwd = "password"; + Wallet wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); Kernel kernel = new Kernel(config); @@ -251,7 +256,7 @@ public Kernel createKernel(TemporaryFolder root) throws Exception { kernel.setBlockStore(blockStore); kernel.setOrphanPool(orphanPool); - kernel.setWallet(xdagWallet); + kernel.setWallet(wallet); RandomX randomX = new RandomX(config); kernel.setRandomXUtils(randomX); diff --git a/src/test/java/io/xdag/core/RewardTest.java b/src/test/java/io/xdag/core/RewardTest.java index a43386ca..092728c0 100644 --- a/src/test/java/io/xdag/core/RewardTest.java +++ b/src/test/java/io/xdag/core/RewardTest.java @@ -29,6 +29,7 @@ import io.xdag.config.DevnetConfig; import io.xdag.config.RandomXConstants; import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.SampleKeys; import io.xdag.crypto.jni.Native; import io.xdag.db.DatabaseFactory; import io.xdag.db.DatabaseName; @@ -36,16 +37,19 @@ import io.xdag.db.store.BlockStore; import io.xdag.db.store.OrphanPool; import io.xdag.randomx.RandomX; +import io.xdag.utils.Numeric; import io.xdag.utils.XdagTime; -import io.xdag.wallet.OldWallet; -import org.apache.commons.lang3.time.FastDateFormat; +import io.xdag.wallet.Wallet; +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.text.ParseException; +import java.util.Collections; import java.util.List; import static io.xdag.BlockBuilder.*; @@ -55,14 +59,12 @@ import static org.junit.Assert.assertTrue; public class RewardTest { - @Rule public TemporaryFolder root = new TemporaryFolder(); - public static FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss"); - Config config = new DevnetConfig(); - OldWallet xdagWallet; + Wallet wallet; + String pwd; Kernel kernel; DatabaseFactory dbFactory; @@ -92,8 +94,12 @@ public void setUp() throws Exception { if (Native.dnet_crypt_init() < 0) { throw new Exception("dnet crypt init failed"); } - xdagWallet = new OldWallet(); - xdagWallet.init(config); + pwd = "password"; + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); kernel = new Kernel(config); dbFactory = new RocksdbFactory(config); @@ -109,7 +115,12 @@ public void setUp() throws Exception { kernel.setBlockStore(blockStore); kernel.setOrphanPool(orphanPool); - kernel.setWallet(xdagWallet); + kernel.setWallet(wallet); + } + + @After + public void tearDown() throws IOException { + wallet.delete(); } @Test diff --git a/src/test/java/io/xdag/crypto/CredentialsTest.java b/src/test/java/io/xdag/crypto/CredentialsTest.java deleted file mode 100644 index 49e3df30..00000000 --- a/src/test/java/io/xdag/crypto/CredentialsTest.java +++ /dev/null @@ -1,51 +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 org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class CredentialsTest { - - @Test - public void testCredentialsFromString() { - Credentials credentials = Credentials.create(SampleKeys.KEY_PAIR); - verify(credentials); - } - - @Test - public void testCredentialsFromECKeyPair() { - Credentials credentials = - Credentials.create(SampleKeys.PRIVATE_KEY_STRING, SampleKeys.PUBLIC_KEY_STRING); - verify(credentials); - } - - private void verify(Credentials credentials) { - assertEquals(credentials.getAddress(), (SampleKeys.ADDRESS)); - assertEquals(credentials.getEcKeyPair(), (SampleKeys.KEY_PAIR)); - } -} - diff --git a/src/test/java/io/xdag/crypto/ECRecoverTest.java b/src/test/java/io/xdag/crypto/ECRecoverTest.java deleted file mode 100644 index eff9c7f6..00000000 --- a/src/test/java/io/xdag/crypto/ECRecoverTest.java +++ /dev/null @@ -1,87 +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 io.xdag.utils.Numeric; -import org.junit.Test; - -import java.math.BigInteger; -import java.util.Arrays; - -import static org.junit.Assert.*; -import static io.xdag.crypto.Sign.*; - -public class ECRecoverTest { - public static final String PERSONAL_MESSAGE_PREFIX = "\u0019Xdag Signed Message:\n"; - - @Test - public void testRecoverAddressFromSignature() { - - String signature = - "0x2c6401216c9031b9a6fb8cbfccab4fcec6c951cdf40e2320108d1856eb532250576865fbcd452bcdc4c57321b619ed7a9cfd38bd973c3e1e0243ac2777fe9d5b1b"; - - String address = "0x217a803b41360b20672ef423c76aa0a128fc3563"; - String message = "v0G9u7huK4mJb2K1"; - - String prefix = PERSONAL_MESSAGE_PREFIX + message.length(); - byte[] msgHash = Hash.sha256((prefix + message).getBytes()); - - byte[] signatureBytes = Numeric.hexStringToByteArray(signature); - byte v = signatureBytes[64]; - if (v < 27) { - v += 27; - } - - SignatureData sd = - new SignatureData( - v, - Arrays.copyOfRange(signatureBytes, 0, 32), - Arrays.copyOfRange(signatureBytes, 32, 64)); - - String addressRecovered = null; - boolean match = false; - - // Iterate for each possible key to recover - for (int i = 0; i < 4; i++) { - BigInteger publicKey = - recoverFromSignature( - (byte) i, - new ECDSASignature( - new BigInteger(1, sd.getR()), new BigInteger(1, sd.getS())), - msgHash); - - if (publicKey != null) { - addressRecovered = "0x" + Keys.getAddress(publicKey); - - if (addressRecovered.equals(address)) { - match = true; - break; - } - } - } - - assertEquals(addressRecovered, (address)); - assertTrue(match); - } -} diff --git a/src/test/java/io/xdag/crypto/KeysTest.java b/src/test/java/io/xdag/crypto/KeysTest.java index b903c69c..faa1a25d 100644 --- a/src/test/java/io/xdag/crypto/KeysTest.java +++ b/src/test/java/io/xdag/crypto/KeysTest.java @@ -70,63 +70,4 @@ public void testCreateEcKeyPair() throws Exception { assertEquals(ecKeyPair.getPrivateKey().signum(), (1)); } - @Test - public void testGetAddressString() { - assertEquals(Keys.getAddress(SampleKeys.PUBLIC_KEY_STRING), (SampleKeys.ADDRESS_NO_PREFIX)); - } - - @Test - public void testGetAddressZeroPaddedAddress() { - String publicKey = - "0xa1b31be4d58a7ddd24b135db0da56a90fb5382077ae26b250e1dc9cd6232ce22" - + "70f4c995428bc76aa78e522316e95d7834d725efc9ca754d043233af6ca90113"; - assertEquals(Keys.getAddress(publicKey), ("9bc8beec6d9aed67d23218941ac5fb60a1960a0c")); - } - - @Test - public void testGetAddressBigInteger() { - assertEquals(Keys.getAddress(SampleKeys.PUBLIC_KEY), (SampleKeys.ADDRESS_NO_PREFIX)); - } - - @Test - public void testGetAddressSmallPublicKey() { - byte[] address = - Keys.getAddress( - Numeric.toBytesPadded(BigInteger.valueOf(0x1234), Keys.PUBLIC_KEY_SIZE)); - String expected = Numeric.toHexStringNoPrefix(address); - - assertEquals(Keys.getAddress("0x1234"), (expected)); - } - - @Test - public void testGetAddressZeroPadded() { - byte[] address = - Keys.getAddress( - Numeric.toBytesPadded(BigInteger.valueOf(0x1234), Keys.PUBLIC_KEY_SIZE)); - String expected = Numeric.toHexStringNoPrefix(address); - - String value = "1234"; - assertEquals( - Keys.getAddress( - "0x" - + Strings.zeros(Keys.PUBLIC_KEY_LENGTH_IN_HEX - value.length()) - + value), - (expected)); - } - - @Test - public void testSerializeECKey() { - assertArrayEquals(Keys.serialize(SampleKeys.KEY_PAIR), (ENCODED)); - } - - @Test - public void testDeserializeECKey() { - assertEquals(Keys.deserialize(ENCODED), (SampleKeys.KEY_PAIR)); - } - - @Test - public void testDeserializeInvalidKey() { - assertThrows(RuntimeException.class, () -> Keys.deserialize(new byte[0])); - } - } diff --git a/src/test/java/io/xdag/crypto/SampleKeys.java b/src/test/java/io/xdag/crypto/SampleKeys.java index d9069b2d..5b689b15 100644 --- a/src/test/java/io/xdag/crypto/SampleKeys.java +++ b/src/test/java/io/xdag/crypto/SampleKeys.java @@ -36,7 +36,7 @@ public class SampleKeys { public static final String PUBLIC_KEY_STRING = "0x506bc1dc099358e5137292f4efdd57e400f29ba5132aa5d12b18dac1c1f6aab" + "a645c0b7b58158babbfa6c6cd5a48aa7340a8749176b120e8516216787a13dc76"; - public static final String ADDRESS = "0xa15339b55796b3585127c180fd4cbc54612122cf"; + public static final String ADDRESS = "0xb731bf10ed204f4ebc3d32ac88b7aa61b993fd59"; public static final String ADDRESS_NO_PREFIX = Numeric.cleanHexPrefix(ADDRESS); public static final String PASSWORD = "Insecure Pa55w0rd"; @@ -49,8 +49,6 @@ public class SampleKeys { public static final ECKeyPair KEY_PAIR = new ECKeyPair(PRIVATE_KEY, PUBLIC_KEY); - public static final Credentials CREDENTIALS = Credentials.create(KEY_PAIR); - private SampleKeys() {} } diff --git a/src/test/java/io/xdag/mine/miner/MinerConnectTest.java b/src/test/java/io/xdag/mine/miner/MinerConnectTest.java index 7c2c6f74..adc96b89 100644 --- a/src/test/java/io/xdag/mine/miner/MinerConnectTest.java +++ b/src/test/java/io/xdag/mine/miner/MinerConnectTest.java @@ -30,9 +30,13 @@ import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.config.DevnetConfig; -import io.xdag.core.*; +import io.xdag.core.Block; +import io.xdag.core.BlockchainImpl; +import io.xdag.core.ImportResult; +import io.xdag.core.XdagBlock; import io.xdag.crypto.ECKeyPair; import io.xdag.crypto.Keys; +import io.xdag.crypto.SampleKeys; import io.xdag.crypto.jni.Native; import io.xdag.db.DatabaseFactory; import io.xdag.db.DatabaseName; @@ -42,13 +46,17 @@ import io.xdag.mine.MinerChannel; import io.xdag.mine.handler.MinerHandShakeHandler; import io.xdag.utils.BytesUtils; -import io.xdag.wallet.OldWallet; +import io.xdag.utils.Numeric; +import io.xdag.wallet.Wallet; import org.bouncycastle.util.encoders.Hex; +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.util.Collections; import java.util.Date; import java.util.List; @@ -62,7 +70,8 @@ public class MinerConnectTest { public TemporaryFolder root = new TemporaryFolder(); Config config = new DevnetConfig(); - OldWallet xdagWallet; + Wallet wallet; + String pwd; Kernel kernel; DatabaseFactory dbFactory; MinerChannel channel; @@ -77,8 +86,12 @@ public void setUp() throws Exception { if (Native.dnet_crypt_init() < 0) { throw new Exception("dnet crypt init failed"); } - xdagWallet = new OldWallet(); - xdagWallet.init(config); + pwd = "password"; + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); kernel = new Kernel(config); dbFactory = new RocksdbFactory(config); @@ -94,13 +107,18 @@ public void setUp() throws Exception { kernel.setBlockStore(blockStore); kernel.setOrphanPool(orphanPool); - kernel.setWallet(xdagWallet); + kernel.setWallet(wallet); blockchain = new BlockchainImpl(kernel); channel = new MinerChannel(kernel,null,false); } + @After + public void tearDown() throws IOException { + wallet.delete(); + } + class MockMinerHandshakeHandler extends MinerHandShakeHandler{ public MockMinerHandshakeHandler(MinerChannel channel, Kernel kernel) { diff --git a/src/test/java/io/xdag/wallet/Bip44WalletUtilsTest.java b/src/test/java/io/xdag/wallet/Bip44WalletUtilsTest.java deleted file mode 100644 index 18479631..00000000 --- a/src/test/java/io/xdag/wallet/Bip44WalletUtilsTest.java +++ /dev/null @@ -1,109 +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.wallet; - -import io.xdag.crypto.Base58; -import io.xdag.crypto.Bip32ECKeyPair; -import io.xdag.crypto.Credentials; -import io.xdag.crypto.MnemonicUtils; -import io.xdag.utils.BytesUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import static org.junit.Assert.assertEquals; -import static io.xdag.crypto.Bip32Test.addChecksum; -import static io.xdag.crypto.Bip32Test.serializePrivate; -import static io.xdag.crypto.Bip32Test.serializePublic; -import static io.xdag.crypto.SampleKeys.PASSWORD; - -public class Bip44WalletUtilsTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Test - public void generateBip44KeyPair() { - String mnemonic = "spider elbow fossil truck deal circle divert sleep safe report laundry above"; - byte[] seed = MnemonicUtils.generateSeed(mnemonic, null); - String seedStr = BytesUtils.toHexString(seed); - assertEquals( - "f0d2ab78b96acd147119abad1cd70eb4fec4f0e0a95744cf532e6a09347b08101213b4cbf50eada0eb89cba444525fe28e69707e52aa301c6b47ce1c5ef82eb5", - seedStr); - - Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); - assertEquals( - "xprv9s21ZrQH143K2yA9Cdad5gjqHRC7apVUgEyYq5jXeXigDZ3PfEnps44tJprtMXr7PZivEsin6Qrbad7PuiEy4tn5jAEK6A3U46f9KvfRCmD", - Base58.encode(addChecksum(serializePrivate(masterKeypair)))); - - Bip32ECKeyPair bip44Keypair = Bip44WalletUtils.generateBip44KeyPair(masterKeypair); - - assertEquals( - "xprvA3bRNS6bxNHSZQvJrLiPhVePhqy69cdmsJ2oa2XuMcyuiMDn13ZAVsVDWyQRHZLJrQMMs3qUEf6GDarnJpzBKHXVFcLZgvkD9oGDR845BTL", - Base58.encode(addChecksum(serializePrivate(bip44Keypair)))); - assertEquals( - "xpub6GammwdVnjqjmtzmxNFQ4db8FsoaZ5MdEWxQNQwWuxWtb9YvYasR3fohNEiSmcG4pzTziN62M3LZvEowb74cgqW78BLZayCgBDRuGH89xni", - Base58.encode(addChecksum(serializePublic(bip44Keypair)))); - - // Verify address according to https://iancoleman.io/bip39/ - Credentials credentials = Bip44WalletUtils.loadBip44Credentials("", mnemonic); - assertEquals("0xddc049a60750affe6f53b1d77208e4108f14d742", credentials.getAddress().toLowerCase()); - } - - @Test - public void generateBip44KeyPairTestNet() { - String mnemonic = - "spider elbow fossil truck deal circle divert sleep safe report laundry above"; - byte[] seed = MnemonicUtils.generateSeed(mnemonic, null); - String seedStr = BytesUtils.toHexString(seed); - assertEquals( - "f0d2ab78b96acd147119abad1cd70eb4fec4f0e0a95744cf532e6a09347b08101213b4cbf50eada0eb89cba444525fe28e69707e52aa301c6b47ce1c5ef82eb5", - seedStr); - - Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); - assertEquals( - "xprv9s21ZrQH143K2yA9Cdad5gjqHRC7apVUgEyYq5jXeXigDZ3PfEnps44tJprtMXr7PZivEsin6Qrbad7PuiEy4tn5jAEK6A3U46f9KvfRCmD", - Base58.encode(addChecksum(serializePrivate(masterKeypair)))); - - Bip32ECKeyPair bip44Keypair = Bip44WalletUtils.generateBip44KeyPair(masterKeypair); - - assertEquals( - "xprvA3bRNS6bxNHSZQvJrLiPhVePhqy69cdmsJ2oa2XuMcyuiMDn13ZAVsVDWyQRHZLJrQMMs3qUEf6GDarnJpzBKHXVFcLZgvkD9oGDR845BTL", - Base58.encode(addChecksum(serializePrivate(bip44Keypair)))); - assertEquals( - "xpub6GammwdVnjqjmtzmxNFQ4db8FsoaZ5MdEWxQNQwWuxWtb9YvYasR3fohNEiSmcG4pzTziN62M3LZvEowb74cgqW78BLZayCgBDRuGH89xni", - Base58.encode(addChecksum(serializePublic(bip44Keypair)))); - } - - @Test - public void testGenerateBip44Wallets() throws Exception { - Bip39Wallet wallet = Bip44WalletUtils.generateBip44Wallet(PASSWORD, temporaryFolder.newFolder()); - byte[] seed = MnemonicUtils.generateSeed(wallet.getMnemonic(), PASSWORD); - Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); - Bip32ECKeyPair bip44Keypair = Bip44WalletUtils.generateBip44KeyPair(masterKeypair); - Credentials credentials = Credentials.create(bip44Keypair); - assertEquals(credentials, Bip44WalletUtils.loadBip44Credentials(PASSWORD, wallet.getMnemonic())); - } -} - diff --git a/src/test/java/io/xdag/wallet/WalletFileTest.java b/src/test/java/io/xdag/wallet/WalletFileTest.java deleted file mode 100644 index a003bc65..00000000 --- a/src/test/java/io/xdag/wallet/WalletFileTest.java +++ /dev/null @@ -1,87 +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.wallet; - -import com.fasterxml.jackson.databind.ObjectMapper; -import io.xdag.wallet.WalletFile; -import org.junit.Test; - -import java.io.IOException; - -import static org.junit.Assert.assertEquals; - -public class WalletFileTest { - - @Test - public void equalsAndHashCodeTest() throws IOException { - - final String AES_128_CTR = - "{\n" - + " \"crypto\" : {\n" - + " \"cipher\" : \"aes-128-ctr\",\n" - + " \"cipherparams\" : {\n" - + " \"iv\" : \"02ebc768684e5576900376114625ee6f\"\n" - + " },\n" - + " \"ciphertext\" : \"7ad5c9dd2c95f34a92ebb86740b92103a5d1cc4c2eabf3b9a59e1f83f3181216\",\n" - + " \"kdf\" : \"pbkdf2\",\n" - + " \"kdfparams\" : {\n" - + " \"c\" : 262144,\n" - + " \"dklen\" : 32,\n" - + " \"prf\" : \"hmac-sha256\",\n" - + " \"salt\" : \"0e4cf3893b25bb81efaae565728b5b7cde6a84e224cbf9aed3d69a31c981b702\"\n" - + " },\n" - + " \"mac\" : \"2b29e4641ec17f4dc8b86fc8592090b50109b372529c30b001d4d96249edaf62\"\n" - + " },\n" - + " \"id\" : \"af0451b4-6020-4ef0-91ec-794a5a965b01\",\n" - + " \"version\" : 3\n" - + "}"; - ObjectMapper objectMapper = new ObjectMapper(); - WalletFile walletFile1 = objectMapper.readValue(AES_128_CTR, WalletFile.class); - - WalletFile.Crypto crypto = new WalletFile.Crypto(); - crypto.setCipher("aes-128-ctr"); - crypto.setCiphertext("7ad5c9dd2c95f34a92ebb86740b92103a5d1cc4c2eabf3b9a59e1f83f3181216"); - crypto.setKdf("pbkdf2"); - crypto.setMac("2b29e4641ec17f4dc8b86fc8592090b50109b372529c30b001d4d96249edaf62"); - - WalletFile.CipherParams cipherParams = new WalletFile.CipherParams(); - cipherParams.setIv("02ebc768684e5576900376114625ee6f"); - crypto.setCipherparams(cipherParams); - - WalletFile.Aes128CtrKdfParams kdfParams = new WalletFile.Aes128CtrKdfParams(); - kdfParams.setC(262144); - kdfParams.setDklen(32); - kdfParams.setPrf("hmac-sha256"); - kdfParams.setSalt("0e4cf3893b25bb81efaae565728b5b7cde6a84e224cbf9aed3d69a31c981b702"); - crypto.setKdfparams(kdfParams); - - WalletFile walletFile2 = new WalletFile(); - walletFile2.setCrypto(crypto); - walletFile2.setVersion(3); - walletFile2.setId("af0451b4-6020-4ef0-91ec-794a5a965b01"); - - assertEquals(walletFile1, walletFile2); - assertEquals(walletFile1.hashCode(), walletFile2.hashCode()); - } -} diff --git a/src/test/java/io/xdag/wallet/WalletManagerTest.java b/src/test/java/io/xdag/wallet/WalletManagerTest.java deleted file mode 100644 index 65f3d8f0..00000000 --- a/src/test/java/io/xdag/wallet/WalletManagerTest.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.wallet; - -import io.xdag.crypto.*; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Optional; - -import static io.xdag.crypto.SampleKeys.PASSWORD; -import static org.junit.Assert.*; - - -public class WalletManagerTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Test - public void testCreateBip44Wallet() throws IOException, CipherException { - Optional c = WalletManager.createBip44Wallet("xdagTotheMoon", temporaryFolder.newFolder()); - assertNotNull(c.get()); - } - - @Test - public void testImportBip44WalletFromMnemonic() { - String mnemonic = "spider elbow fossil truck deal circle divert sleep safe report laundry above"; - Optional c = WalletManager.importBip44WalletFromMnemonic("", mnemonic); - Credentials credentials = c.get(); - assertEquals("0xddc049a60750affe6f53b1d77208e4108f14d742", credentials.getAddress().toLowerCase()); - } - - @Test - public void testImportBip44WalletFromKeystore() throws IOException, CipherException { - InputStream in = WalletUtilsTest.class.getResourceAsStream( - "/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json"); - String keystore = WalletUtilsTest.convertStreamToString(in); - Optional c = WalletManager.importBip44WalletFromKeystore(PASSWORD, keystore); - assertEquals(c.get(), SampleKeys.CREDENTIALS); - } -} diff --git a/src/test/java/io/xdag/wallet/WalletTest.java b/src/test/java/io/xdag/wallet/WalletTest.java index c6e283cf..5a1582ca 100644 --- a/src/test/java/io/xdag/wallet/WalletTest.java +++ b/src/test/java/io/xdag/wallet/WalletTest.java @@ -23,91 +23,176 @@ */ package io.xdag.wallet; -import java.io.IOException; - -import com.fasterxml.jackson.databind.ObjectMapper; - +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.Keys; import io.xdag.crypto.SampleKeys; import io.xdag.utils.Numeric; + +import org.apache.commons.collections4.CollectionUtils; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; public class WalletTest { + private String pwd; + private Wallet wallet; + private Config config; + + @Before + public void setUp() { + pwd = "password"; + config = new DevnetConfig(); + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); + wallet.lock(); + } + + @Test + public void testGetters() { + wallet.unlock(pwd); + assertEquals(pwd, wallet.getPassword()); + } + @Test - public void testCreateStandard() throws Exception { - testCreate(Wallet.createStandard(SampleKeys.PASSWORD, SampleKeys.KEY_PAIR)); + public void testUnlock() { + assertFalse(wallet.isUnlocked()); + + wallet.unlock(pwd); + assertTrue(wallet.isUnlocked()); + + assertEquals(1, wallet.getAccounts().size()); } @Test - public void testCreateLight() throws Exception { - testCreate(Wallet.createLight(SampleKeys.PASSWORD, SampleKeys.KEY_PAIR)); + public void testLock() { + wallet.unlock(pwd); + wallet.lock(); + assertFalse(wallet.isUnlocked()); } - private void testCreate(WalletFile walletFile) throws Exception { - assertEquals(walletFile.getAddress(), (SampleKeys.ADDRESS_NO_PREFIX)); + @Test + public void testAddAccounts() { + wallet.unlock(pwd); + wallet.setAccounts(Collections.emptyList()); + ECKeyPair key1 = Keys.createEcKeyPair(); + ECKeyPair key2 = Keys.createEcKeyPair(); + wallet.addAccounts(Arrays.asList(key1, key2)); + List accounts = wallet.getAccounts(); + ECKeyPair k1 = accounts.get(0); + ECKeyPair k2 = accounts.get(1); + assertEquals(k1, key1); + assertEquals(k2, key2); } @Test - public void testEncryptDecryptStandard() throws Exception { - testEncryptDecrypt(Wallet.createStandard(SampleKeys.PASSWORD, SampleKeys.KEY_PAIR)); + public void testFlush() throws InterruptedException { + File file = wallet.getFile(); + long sz = wallet.getFile().length(); + Thread.sleep(500); + + wallet.unlock(pwd); + wallet.setAccounts(Collections.emptyList()); + assertEquals(sz, file.length()); + + wallet.flush(); + assertTrue(file.length() < sz); } @Test - public void testEncryptDecryptLight() throws Exception { - testEncryptDecrypt(Wallet.createLight(SampleKeys.PASSWORD, SampleKeys.KEY_PAIR)); + public void testChangePassword() { + String pwd2 = "passw0rd2"; + + wallet.unlock(pwd); + wallet.changePassword(pwd2); + wallet.flush(); + wallet.lock(); + + assertFalse(wallet.unlock(pwd)); + assertTrue(wallet.unlock(pwd2)); } - private void testEncryptDecrypt(WalletFile walletFile) throws Exception { - assertEquals(Wallet.decrypt(SampleKeys.PASSWORD, walletFile), (SampleKeys.KEY_PAIR)); + @Test + public void testAddAccountRandom() { + wallet.unlock(pwd); + int oldAccountSize = wallet.getAccounts().size(); + wallet.addAccountRandom(); + assertEquals(oldAccountSize + 1, wallet.getAccounts().size()); } @Test - public void testDecryptScrypt() throws Exception { - WalletFile walletFile = load(SCRYPT); - ECKeyPair ecKeyPair = Wallet.decrypt(PASSWORD, walletFile); - assertEquals(Numeric.toHexStringNoPrefix(ecKeyPair.getPrivateKey()), (SECRET)); + public void testRemoveAccount() { + wallet.unlock(pwd); + int oldAccountSize = wallet.getAccounts().size(); + ECKeyPair key = Keys.createEcKeyPair(); + wallet.addAccount(key); + assertEquals(oldAccountSize + 1, wallet.getAccounts().size()); + wallet.removeAccount(key); + assertEquals(oldAccountSize, wallet.getAccounts().size()); + wallet.addAccount(key); + assertEquals(oldAccountSize + 1, wallet.getAccounts().size()); + wallet.removeAccount(Keys.toBytesAddress(key)); + assertEquals(oldAccountSize, wallet.getAccounts().size()); } @Test - public void testGenerateRandomBytes() { - assertArrayEquals(Wallet.generateRandomBytes(0), (new byte[] {})); - assertEquals(Wallet.generateRandomBytes(10).length, (10)); + public void testInitializeHdWallet() { + wallet.initializeHdWallet(SampleKeys.MNEMONIC); + assertEquals(0, wallet.getNextAccountIndex()); + assertEquals(SampleKeys.MNEMONIC,wallet.getMnemonicPhrase()); } - private WalletFile load(String source) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(source, WalletFile.class); + @Test + public void testAddAccountWithNextHdKey() { + wallet.unlock(pwd); + wallet.initializeHdWallet(SampleKeys.MNEMONIC); + int hdkeyCount = 5; + for(int i = 0; i < hdkeyCount; i++) { + wallet.addAccountWithNextHdKey(); + } + assertEquals(hdkeyCount, wallet.getNextAccountIndex()); } - private static final String PASSWORD = "Insecure Pa55w0rd"; - private static final String SECRET = - "a392604efc2fad9c0b3da43b5f698a2e3f270f170d859912be0d54742275c5f6"; - - private static final String SCRYPT = - "{\n" - + " \"crypto\" : {\n" - + " \"cipher\" : \"aes-128-ctr\",\n" - + " \"cipherparams\" : {\n" - + " \"iv\" : \"525d33d781892fc3c743520a248c9cd5\"\n" - + " },\n" - + " \"ciphertext\" : \"3c56840c492c27efeb6ded513b5816996ae10589bbd9c9662b3f1e6158729b98\",\n" - + " \"kdf\" : \"scrypt\",\n" - + " \"kdfparams\" : {\n" - + " \"dklen\" : 32,\n" - + " \"n\" : 262144,\n" - + " \"r\" : 8,\n" - + " \"p\" : 1,\n" - + " \"salt\" : \"08cbb63ad8140ea2a6dedd69a723d668e83f950008049601f726660d6d50c2c8\"\n" - + " },\n" - + " \"mac\" : \"4691e03401d5b095a16c20cf185628cfa2d0b159021d7bc3fccac6478ce21c32\"\n" - + " },\n" - + " \"id\" : \"18153e96-657a-498e-a954-cba7e85d47b9\",\n" - + " \"version\" : 3\n" - + "}"; + @Test + public void testHDKeyRecover() { + wallet.unlock(pwd); + wallet.initializeHdWallet(SampleKeys.MNEMONIC); + List keyPairList1 = new ArrayList<>(); + int hdkeyCount = 5; + for(int i = 0; i < hdkeyCount; i++) { + ECKeyPair key = wallet.addAccountWithNextHdKey(); + keyPairList1.add(key); + } + + assertEquals(hdkeyCount, wallet.getNextAccountIndex()); + Wallet wallet2 = new Wallet(config); + // use different password and same mnemonic + wallet2.unlock(pwd + pwd); + wallet2.initializeHdWallet(SampleKeys.MNEMONIC); + List keyPairList2 = new ArrayList<>(); + for(int i = 0; i < hdkeyCount; i++) { + ECKeyPair key = wallet2.addAccountWithNextHdKey(); + keyPairList2.add(key); + } + assertTrue(CollectionUtils.isEqualCollection(keyPairList1, keyPairList2)); + } + @After + public void tearDown() throws IOException { + wallet.delete(); + } } - diff --git a/src/test/java/io/xdag/wallet/WalletUtilsTest.java b/src/test/java/io/xdag/wallet/WalletUtilsTest.java index 0463edc5..d9e4822c 100644 --- a/src/test/java/io/xdag/wallet/WalletUtilsTest.java +++ b/src/test/java/io/xdag/wallet/WalletUtilsTest.java @@ -23,217 +23,102 @@ */ package io.xdag.wallet; +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; import io.xdag.crypto.*; +import io.xdag.utils.BytesUtils; import io.xdag.utils.Numeric; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; -import java.io.File; -import java.nio.file.Files; - - - +import java.io.IOException; +import java.util.Collections; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static io.xdag.crypto.Hash.sha256; -import static io.xdag.crypto.SampleKeys.CREDENTIALS; -import static io.xdag.crypto.SampleKeys.KEY_PAIR; -import static io.xdag.crypto.SampleKeys.MNEMONIC; -import static io.xdag.crypto.SampleKeys.PASSWORD; -import static io.xdag.wallet.WalletUtils.isValidAddress; -import static io.xdag.wallet.WalletUtils.isValidPrivateKey; +import static io.xdag.crypto.Bip32Test.addChecksum; +import static io.xdag.crypto.Bip32Test.serializePrivate; +import static io.xdag.crypto.Bip32Test.serializePublic; public class WalletUtilsTest { - private File tempDir; + private String pwd; + private Wallet wallet; - public static String convertStreamToString(java.io.InputStream is) { - java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); - return s.hasNext() ? s.next() : ""; - } + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before - public void setUp() throws Exception { - tempDir = createTempDir(); - } - - @After - public void tearDown() throws Exception { - for (File file : tempDir.listFiles()) { - file.delete(); - } - tempDir.delete(); - } - - @Test - public void testGenerateBip39Wallets() throws Exception { - Bip39Wallet wallet = WalletUtils.generateBip39Wallet(PASSWORD, tempDir); - byte[] seed = MnemonicUtils.generateSeed(wallet.getMnemonic(), PASSWORD); - Credentials credentials = Credentials.create(ECKeyPair.create(sha256(seed))); - - assertEquals(credentials, WalletUtils.loadBip39Credentials(PASSWORD, wallet.getMnemonic())); - } - - @Test - public void testGenerateBip39WalletFromMnemonic() throws Exception { - Bip39Wallet wallet = - WalletUtils.generateBip39WalletFromMnemonic(PASSWORD, MNEMONIC, tempDir); - byte[] seed = MnemonicUtils.generateSeed(wallet.getMnemonic(), PASSWORD); - Credentials credentials = Credentials.create(ECKeyPair.create(sha256(seed))); - - assertEquals(credentials, WalletUtils.loadBip39Credentials(PASSWORD, wallet.getMnemonic())); - } - - @Test - public void testGenerateFullNewWalletFile() throws Exception { - String fileName = WalletUtils.generateFullNewWalletFile(PASSWORD, tempDir); - testGeneratedNewWalletFile(fileName); - } - - @Test - public void testGenerateNewWalletFile() throws Exception { - String fileName = WalletUtils.generateNewWalletFile(PASSWORD, tempDir); - testGeneratedNewWalletFile(fileName); - } - - @Test - public void testGenerateLightNewWalletFile() throws Exception { - String fileName = WalletUtils.generateLightNewWalletFile(PASSWORD, tempDir); - testGeneratedNewWalletFile(fileName); - } - - private void testGeneratedNewWalletFile(String fileName) throws Exception { - WalletUtils.loadCredentials(PASSWORD, new File(tempDir, fileName)); - } - - @Test - public void testGenerateFullWalletFile() throws Exception { - String fileName = WalletUtils.generateWalletFile(PASSWORD, KEY_PAIR, tempDir, true); - testGenerateWalletFile(fileName); + public void setUp() { + pwd = "password"; + Config config = new DevnetConfig(); + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); + wallet.lock(); } @Test - public void testGenerateLightWalletFile() throws Exception { - String fileName = WalletUtils.generateWalletFile(PASSWORD, KEY_PAIR, tempDir, false); - testGenerateWalletFile(fileName); - } + public void generateBip44KeyPair() { - private void testGenerateWalletFile(String fileName) throws Exception { - Credentials credentials = - WalletUtils.loadCredentials(PASSWORD, new File(tempDir, fileName)); - - assertEquals(credentials, (CREDENTIALS)); - } - - @Test - public void testLoadCredentialsFromFile() throws Exception { - Credentials credentials = - WalletUtils.loadCredentials( - PASSWORD, - new File( - WalletUtilsTest.class - .getResource( - "/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json") - .getFile())); - - assertEquals(credentials, (CREDENTIALS)); - } + String mnemonic = "spider elbow fossil truck deal circle divert sleep safe report laundry above"; + byte[] seed = MnemonicUtils.generateSeed(mnemonic, null); + String seedStr = BytesUtils.toHexString(seed); + assertEquals( + "f0d2ab78b96acd147119abad1cd70eb4fec4f0e0a95744cf532e6a09347b08101213b4cbf50eada0eb89cba444525fe28e69707e52aa301c6b47ce1c5ef82eb5", + seedStr); - @Test - public void testLoadCredentialsFromString() throws Exception { - Credentials credentials = - WalletUtils.loadCredentials( - PASSWORD, - WalletUtilsTest.class - .getResource( - "/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json") - .getFile()); - - assertEquals(credentials, (CREDENTIALS)); - } + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + assertEquals( + "xprv9s21ZrQH143K2yA9Cdad5gjqHRC7apVUgEyYq5jXeXigDZ3PfEnps44tJprtMXr7PZivEsin6Qrbad7PuiEy4tn5jAEK6A3U46f9KvfRCmD", + Base58.encode(addChecksum(serializePrivate(masterKeypair)))); - @Test - public void testLoadCredentialsMyEtherWallet() throws Exception { - Credentials credentials = - WalletUtils.loadCredentials( - PASSWORD, - new File( - WalletUtilsTest.class - .getResource( - "/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json") - .getFile())); + Bip32ECKeyPair bip44Keypair = WalletUtils.generateBip44KeyPair(masterKeypair,0); assertEquals( - credentials, - (Credentials.create( - "a392604efc2fad9c0b3da43b5f698a2e3f270f170d859912be0d54742275c5f6"))); - } - - @Test - public void testLoadJsonCredentials() throws Exception { - Credentials credentials = - WalletUtils.loadJsonCredentials( - PASSWORD, - convertStreamToString( - WalletUtilsTest.class.getResourceAsStream( - "/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json"))); - - assertEquals(credentials, (CREDENTIALS)); - } + "xprvA3bRNS6bxNHSZQvJrLiPhVePhqy69cdmsJ2oa2XuMcyuiMDn13ZAVsVDWyQRHZLJrQMMs3qUEf6GDarnJpzBKHXVFcLZgvkD9oGDR845BTL", + Base58.encode(addChecksum(serializePrivate(bip44Keypair)))); + assertEquals( + "xpub6GammwdVnjqjmtzmxNFQ4db8FsoaZ5MdEWxQNQwWuxWtb9YvYasR3fohNEiSmcG4pzTziN62M3LZvEowb74cgqW78BLZayCgBDRuGH89xni", + Base58.encode(addChecksum(serializePublic(bip44Keypair)))); - @Test - public void testGetDefaultKeyDirectory() { - assertTrue( - WalletUtils.getDefaultKeyDirectory("Mac OS X") - .endsWith( - String.format( - "%sLibrary%sXdag", File.separator, File.separator))); - assertTrue( - WalletUtils.getDefaultKeyDirectory("Windows") - .endsWith(String.format("%sXdag", File.separator))); - assertTrue( - WalletUtils.getDefaultKeyDirectory("Linux") - .endsWith(String.format("%s.xdag", File.separator))); + // Verify address according to https://iancoleman.io/bip39/ + Bip32ECKeyPair key = WalletUtils.importMnemonic(wallet, pwd, mnemonic, 0); + assertEquals("d85a4d67fcb69b14b12a15ad60e5dc65852f9907", BytesUtils.toHexString(Keys.toBytesAddress(key))); } @Test - public void testGetTestnetKeyDirectory() { - assertTrue( - WalletUtils.getMainnetKeyDirectory() - .endsWith(String.format("%skeystore", File.separator))); - assertTrue( - WalletUtils.getTestnetKeyDirectory() - .endsWith( - String.format( - "%stestnet%skeystore", File.separator, File.separator))); - } + public void generateBip44KeyPairTestNet() { + String mnemonic = + "spider elbow fossil truck deal circle divert sleep safe report laundry above"; + byte[] seed = MnemonicUtils.generateSeed(mnemonic, null); + String seedStr = BytesUtils.toHexString(seed); + assertEquals( + "f0d2ab78b96acd147119abad1cd70eb4fec4f0e0a95744cf532e6a09347b08101213b4cbf50eada0eb89cba444525fe28e69707e52aa301c6b47ce1c5ef82eb5", + seedStr); - static File createTempDir() throws Exception { - return Files.createTempDirectory(WalletUtilsTest.class.getSimpleName() + "-testkeys") - .toFile(); - } + Bip32ECKeyPair masterKeypair = Bip32ECKeyPair.generateKeyPair(seed); + assertEquals( + "xprv9s21ZrQH143K2yA9Cdad5gjqHRC7apVUgEyYq5jXeXigDZ3PfEnps44tJprtMXr7PZivEsin6Qrbad7PuiEy4tn5jAEK6A3U46f9KvfRCmD", + Base58.encode(addChecksum(serializePrivate(masterKeypair)))); - @Test - public void testIsValidPrivateKey() { - assertTrue(isValidPrivateKey(SampleKeys.PRIVATE_KEY_STRING)); - assertTrue(isValidPrivateKey(Numeric.prependHexPrefix(SampleKeys.PRIVATE_KEY_STRING))); + Bip32ECKeyPair bip44Keypair = WalletUtils.generateBip44KeyPair(masterKeypair,0); - assertFalse(isValidPrivateKey("")); - assertFalse(isValidPrivateKey(SampleKeys.PRIVATE_KEY_STRING + "a")); - assertFalse(isValidPrivateKey(SampleKeys.PRIVATE_KEY_STRING.substring(1))); + assertEquals( + "xprvA3bRNS6bxNHSZQvJrLiPhVePhqy69cdmsJ2oa2XuMcyuiMDn13ZAVsVDWyQRHZLJrQMMs3qUEf6GDarnJpzBKHXVFcLZgvkD9oGDR845BTL", + Base58.encode(addChecksum(serializePrivate(bip44Keypair)))); + assertEquals( + "xpub6GammwdVnjqjmtzmxNFQ4db8FsoaZ5MdEWxQNQwWuxWtb9YvYasR3fohNEiSmcG4pzTziN62M3LZvEowb74cgqW78BLZayCgBDRuGH89xni", + Base58.encode(addChecksum(serializePublic(bip44Keypair)))); } - @Test - public void testIsValidAddress() { - assertTrue(isValidAddress(SampleKeys.ADDRESS)); - assertTrue(isValidAddress(SampleKeys.ADDRESS_NO_PREFIX)); - - assertFalse(isValidAddress("")); - assertFalse(isValidAddress(SampleKeys.ADDRESS + 'a')); - assertFalse(isValidAddress(SampleKeys.ADDRESS.substring(1))); + @After + public void tearDown() throws IOException { + wallet.delete(); } } From 91b24c8e572cbab1919a1a568241beed40633332 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 11:33:35 +0800 Subject: [PATCH 05/11] add unittest for rpc --- docs/XDAGJ_Cli_Wallet_eng.md | 173 ++++++++++++++++ pom.xml | 15 +- src/main/java/io/xdag/Kernel.java | 16 +- src/main/java/io/xdag/cli/XdagCli.java | 2 +- src/main/java/io/xdag/cli/XdagOption.java | 2 + .../java/io/xdag/config/AbstractConfig.java | 13 ++ src/main/java/io/xdag/config/Config.java | 1 + src/main/java/io/xdag/core/ImportResult.java | 2 +- .../java/io/xdag/mine/handler/Miner03.java | 2 +- .../io/xdag/rpc/dto/ETHBlockResultDTO.java | 62 ++++++ .../rpc/dto/ETHTransactionReceiptDTO.java | 53 +++++ .../xdag/rpc/dto/TransactionReceiptDTO.java | 92 +++++++++ .../io/xdag/rpc/modules/eth/EthModule.java | 45 ++++ .../rpc/modules/eth/EthModuleTransaction.java | 28 +++ .../xdag/rpc/modules/eth/EthModuleWallet.java | 8 + .../xdag/rpc/modules/web3/Web3EthModule.java | 193 +++++++++--------- .../rpc/modules/web3/Web3EthModuleImpl.java | 69 +++++++ .../rpc/modules/web3/Web3XdagModuleImpl.java | 4 +- .../xdag/XdagModuleTransactionBase.java | 24 ++- .../xdag/XdagModuleTransactionDisabled.java | 5 + .../xdag/XdagModuleTransactionEnabled.java | 16 ++ src/main/resources/xdag-testnet.config | 59 +----- .../java/io/xdag/rpc/Web3XdagModuleTest.java | 90 ++++++++ .../io/xdag/rpc/modules/XdagModuleTest.java | 30 +++ .../io/xdag/rpc/netty/Web3HttpServerTest.java | 172 ++++++++++++++++ .../rpc/netty/Web3WebSocketServerTest.java | 159 +++++++++++++++ 26 files changed, 1169 insertions(+), 166 deletions(-) create mode 100644 docs/XDAGJ_Cli_Wallet_eng.md create mode 100644 src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java create mode 100644 src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java create mode 100644 src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/EthModule.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java create mode 100644 src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java create mode 100644 src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java create mode 100644 src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java create mode 100644 src/test/java/io/xdag/rpc/Web3XdagModuleTest.java create mode 100644 src/test/java/io/xdag/rpc/modules/XdagModuleTest.java create mode 100644 src/test/java/io/xdag/rpc/netty/Web3HttpServerTest.java create mode 100644 src/test/java/io/xdag/rpc/netty/Web3WebSocketServerTest.java diff --git a/docs/XDAGJ_Cli_Wallet_eng.md b/docs/XDAGJ_Cli_Wallet_eng.md new file mode 100644 index 00000000..8564b211 --- /dev/null +++ b/docs/XDAGJ_Cli_Wallet_eng.md @@ -0,0 +1,173 @@ +# XDAGJ Command Line Interface Wallet Tutorial + +This section describes wallet related 'xdag-cli' commands. + +If you want to learn the structure of your Xdag wallet, you can play with the "xdag-cli" wallet commands as shown below. + +- **Please note that at least keep the wallet password and mnemonic phrase, once lost, you cannot retrieve it** +- **This wallet is still in the testing stage, there may be security issues, loss or other unknown issues** + +---------- + +- [System environment](#system-environment) +- [Usage](#usage) +---------- +## System environment + +```yaml + JDK : v15 + script : xdag.sh + jar : xdagj-0.x.y-shaded.jar +``` + +example: +```shell +xdager@localhost xdag_full_node % java --version +openjdk 15.0.2 2021-01-19 +OpenJDK Runtime Environment (build 15.0.2+7) +OpenJDK 64-Bit Server VM (build 15.0.2+7, mixed mode, sharing) +xdager@localhost xdag_full_node % mkdir -p /usr/local/xdag_full_node && cd /usr/local/xdag_full_node +xdager@localhost xdag_full_node % pwd +/usr/local/xdag_full_node +xdager@localhost xdag_full_node % chmod +x xdag.sh +xdager@localhost xdag_full_node % ll +total 95464 +drwxr-xr-x 4 xdager wheel 128 5 24 14:22 . +drwxr-xr-x 16 xdager wheel 512 5 24 14:21 .. +-rwxr-xr-x 1 xdager wheel 275 5 24 14:21 xdag.sh +-rw-r--r-- 1 xdager wheel 48869970 5 24 14:21 xdagj-0.4.2-shaded.jar +``` + +## Usage + +### account + +xdag account initialization and creation, query and other functions + +#### init + +The init action will create an initial mnemonic for HDWallet, please remember the mnemonic for future recovery +The wallet follows the bip44 standard, [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki), [XDAG CoinType](https://github.com/satoshilabs/slips/blob/master/slip-0044.md) + +```yaml +m / purpose' / coin_type' / account' / change / address_index +``` + +```yaml +purporse': Fixed value 44', which means BIP44 +coin_type': This represents the currency, which can be compatible with many currencies, such as BTC is 0', ETH is 60',XDAG is 586' + +btc: m/44'/0'/0'/0 +eth: m/44'/60'/0'/0 +xdag: m/44'/586'/0'/0 +``` + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --account init +EnterNewPassword: +ReEnterNewPassword: +HdWallet Initializing... +HdWallet Mnemonic:smoke that notice super program endless culture bubble trial pass annual rule +HdWallet Mnemonic Repeat:smoke that notice super program endless culture bubble trial pass annual rule +HdWallet Initialized Successfully! +``` + +#### create + +Please note that the create action must be created after the init action, which will follow the bip32 standard, +[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki) and [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) +```shell +xdager@localhost xdag_full_node % ./xdag.sh --account create +Please enter your password: +New Address:89fc1798f2e39687f566db6c02838990206978be +PublicKey:0092909df115b0646f5f771a0505c9c55cc875aeea2a440b7dd11afbd54b350482749d7dba68d1bff96c19adb1a6e920be2e959a684a8ab7545a9a213d85dc4a57 +``` +#### list +The list action will list all addresses in the wallet.data file, including HDWallet and randomly generated addresses +```shell +xdager@localhost xdag_full_node % ./xdag.sh --account list +Please enter your password: +Address:0 89fc1798f2e39687f566db6c02838990206978b +``` + +### changepassword + +This command allows the user to change the password of the wallet.data wallet file generated by xdagj +```shell +xdager@localhost xdag_full_node % ./xdag.sh --changepassword +Please enter your password: +EnterNewPassword +ReEnterNewPassword +Password Changed Successfully! +``` +User needs to enter the old password and the new password, and the two new passwords are the same + +### convertoldwallet + +This command is used to convert the wallet.dat file generated by the old wallet of the xdag c version (please note that the wallet name generated by xdagj is wallet.data). +* Before convert command, you need copy wallet.dat to xdagj working dir. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --convertoldwallet wallet.dat +PrivateKey:4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 + PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 +Old Wallet Converted Successfully! +``` + +### dumpprivatekey + +Dump the private key in hexadecimal string format. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --dumpprivatekey 47af7c90483f95ff030f12458071d0528ac3c5d0 +Private:4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 +Private Dump Successfully! +``` + +### importprivatekey + +Import the private key in hexadecimal string format. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --importprivatekey 4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 +Address:47af7c90483f95ff030f12458071d0528ac3c5d0 +PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 +Private Key Imported Successfully! +``` + +### importmnemonic + +Use mnemonic phrase import to generate new HDWallet. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --importprivatekey 4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 +Address:47af7c90483f95ff030f12458071d0528ac3c5d0 +PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 +HDWallet Mnemonic Imported Successfully! +``` + +### help + +Prompt for command line help information. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --help +usage: ./xdag.sh [options] +--account init|create|list +--changepassword change wallet password +--convertoldwallet convert xdag old wallet.dat to private key hex +--dumpprivatekey
print hex key +--help print help +--importmnemonic import HDWallet mnemonic +--importprivatekey import hex key +--version show version +``` + +### version + +Show xdagj version number. + +```shell +xdager@localhost xdag_full_node % ./xdag.sh --version +0.4.3 +``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9ad25efd..1cc77421 100644 --- a/pom.xml +++ b/pom.xml @@ -433,7 +433,7 @@ com.squareup.okhttp3 okhttp - 4.8.1 + 4.9.1 org.jetbrains @@ -441,6 +441,13 @@ + + + + + + + org.mockito @@ -599,6 +606,12 @@ + + com.sun.xml.ws + jaxws-ri + 2.3.0 + pom + diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 4b5ff070..aa2f2312 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -66,6 +66,7 @@ import io.xdag.rpc.modules.web3.Web3XdagModuleImpl; import io.xdag.rpc.modules.xdag.XdagModule; import io.xdag.rpc.modules.xdag.XdagModuleTransactionDisabled; +import io.xdag.rpc.modules.xdag.XdagModuleTransactionEnabled; import io.xdag.rpc.modules.xdag.XdagModuleWalletDisabled; import io.xdag.rpc.netty.*; import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; @@ -305,8 +306,10 @@ public synchronized void testStart() throws Exception { // ==================================== // rpc start // ==================================== - getWeb3HttpServer().start(); - getWeb3WebSocketServer().start(); + if (config.isRPCEnabled()) { + getWeb3HttpServer().start(); + getWeb3WebSocketServer().start(); + } // ==================================== // telnet server @@ -325,7 +328,7 @@ private Web3 getWeb3() { } private Web3 buildWeb3() { - Web3XdagModule web3XdagModule = new Web3XdagModuleImpl(this.getBlockchain(),new XdagModule((byte) 0x1,new XdagModuleWalletDisabled(),new XdagModuleTransactionDisabled()),this); + Web3XdagModule web3XdagModule = new Web3XdagModuleImpl(new XdagModule((byte) 0x1,new XdagModuleWalletDisabled(),new XdagModuleTransactionEnabled(this.getBlockchain())),this); return new Web3Impl(web3XdagModule); } @@ -358,7 +361,7 @@ private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException private Web3HttpServer getWeb3HttpServer() throws UnknownHostException { if (web3HttpServer == null) { web3HttpServer = new Web3HttpServer( - InetAddress.getByName("127.0.0.1"), + InetAddress.getByName("192.168.3.229"), 4445, 123, true, @@ -375,7 +378,7 @@ private JsonRpcWeb3FilterHandler getJsonRpcWeb3FilterHandler() throws UnknownHos if (jsonRpcWeb3FilterHandler == null) { jsonRpcWeb3FilterHandler = new JsonRpcWeb3FilterHandler( "*", - InetAddress.getByName("127.0.0.1"), + InetAddress.getByName("192.168.3.229"), null ); } @@ -403,6 +406,9 @@ public synchronized void testStop() { if (web3HttpServer != null) { web3HttpServer.stop(); } + if (web3WebSocketServer != null) { + web3WebSocketServer.stop(); + } // 1. 工作层关闭 // stop consensus diff --git a/src/main/java/io/xdag/cli/XdagCli.java b/src/main/java/io/xdag/cli/XdagCli.java index 119f1063..652516c3 100644 --- a/src/main/java/io/xdag/cli/XdagCli.java +++ b/src/main/java/io/xdag/cli/XdagCli.java @@ -483,4 +483,4 @@ public String readPassword(String prompt) { public String readPassword() { return readPassword("Please enter your password: "); } -} \ No newline at end of file +} diff --git a/src/main/java/io/xdag/cli/XdagOption.java b/src/main/java/io/xdag/cli/XdagOption.java index 1fb8d0d2..fd6743e1 100644 --- a/src/main/java/io/xdag/cli/XdagOption.java +++ b/src/main/java/io/xdag/cli/XdagOption.java @@ -41,6 +41,8 @@ public enum XdagOption { IMPORT_MNEMONIC("importmnemonic"), + ENABLE_RPC("enablerpc"), + CONVERT_OLD_WALLET("convertoldwallet"); private final String name; diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index 40bc2192..710f65a1 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -140,6 +140,7 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa // Xdag RPC modules // ========================= protected List moduleDescriptions; + protected boolean rpcEnabled = false; public void setDir() { @@ -249,6 +250,8 @@ public void getSetting() { log.debug("{} IP access", list.length); whiteIPList.addAll(Arrays.asList(list)); } + + rpcEnabled = setting.getBool("isRPCEnabled") != null && setting.getBool("isRPCEnabled"); } @Override @@ -336,6 +339,11 @@ public boolean enableRefresh() { @Override public List getRpcModules() { + + if (!rpcEnabled) { + return null; + } + if (this.moduleDescriptions != null) { return this.moduleDescriptions; } @@ -378,4 +386,9 @@ public List getRpcModules() { return modules; } + + @Override + public boolean isRPCEnabled() { + return rpcEnabled; + } } diff --git a/src/main/java/io/xdag/config/Config.java b/src/main/java/io/xdag/config/Config.java index 41f77121..9460bff0 100644 --- a/src/main/java/io/xdag/config/Config.java +++ b/src/main/java/io/xdag/config/Config.java @@ -83,5 +83,6 @@ public interface Config { // rpc List getRpcModules(); + boolean isRPCEnabled(); } diff --git a/src/main/java/io/xdag/core/ImportResult.java b/src/main/java/io/xdag/core/ImportResult.java index dbc07618..94c61f01 100644 --- a/src/main/java/io/xdag/core/ImportResult.java +++ b/src/main/java/io/xdag/core/ImportResult.java @@ -51,7 +51,7 @@ public String getErrorInfo() { return errorInfo; } - public boolean isIllegal() { + public boolean isLegal() { return this == IMPORTED_NOT_BEST || this == IMPORTED_BEST || this == EXIST; } } diff --git a/src/main/java/io/xdag/mine/handler/Miner03.java b/src/main/java/io/xdag/mine/handler/Miner03.java index ce9cbcbf..a1e45835 100644 --- a/src/main/java/io/xdag/mine/handler/Miner03.java +++ b/src/main/java/io/xdag/mine/handler/Miner03.java @@ -97,7 +97,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { protected void processNewBlock(NewBlockMessage msg) { Block block = msg.getBlock(); ImportResult importResult = syncManager.validateAndAddNewBlock(new BlockWrapper(block, kernel.getConfig().getNodeSpec().getTTL())); - if (importResult.isIllegal()) { + if (importResult.isLegal()) { log.info("XDAG:receive tansaction. A Transaction from wallet/miner, block hash:{}", Hex.toHexString(block.getHash())); } } diff --git a/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java new file mode 100644 index 00000000..1edb3b04 --- /dev/null +++ b/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java @@ -0,0 +1,62 @@ +package io.xdag.rpc.dto; + +import lombok.Data; + +import java.util.Collections; +import java.util.List; + +import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; + +@Data +public class ETHBlockResultDTO { + private final String number; // QUANTITY - the block number. null when its pending block. + private final String hash; // DATA, 32 Bytes - hash of the block. null when its pending block. + private final String parentHash; // DATA, 32 Bytes - hash of the parent block. + private final String sha3Uncles; // DATA, 32 Bytes - SHA3 of the uncles data in the block. + private final String logsBloom; // DATA, 256 Bytes - the bloom filter for the logs of the block. null when its pending block. + private final String transactionsRoot; // DATA, 32 Bytes - the root of the transaction trie of the block. + private final String stateRoot; // DATA, 32 Bytes - the root of the final state trie of the block. + private final String receiptsRoot; // DATA, 32 Bytes - the root of the receipts trie of the block. + private final String miner; // DATA, 20 Bytes - the address of the beneficiary to whom the mining rewards were given. + private final String difficulty; // QUANTITY - integer of the difficulty for this block. + private final String totalDifficulty; // QUANTITY - integer of the total difficulty of the chain until this block. + private final String extraData; // DATA - the "extra data" field of this block + private final String size;//QUANTITY - integer the size of this block in bytes. + private final String gasLimit;//: QUANTITY - the maximum gas allowed in this block. + private final String gasUsed; // QUANTITY - the total used gas by all transactions in this block. + private final String timestamp; //: QUANTITY - the unix timestamp for when the block was collated. + private final List transactions; //: Collection - Collection of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. + private final List uncles; //: Collection - Collection of uncle hashes. + private final String cumulativeDifficulty; + + + public ETHBlockResultDTO( + long timestamp, + List transactions, + List uncles + ) { + this.number = toQuantityJsonHex(12) ; + this.hash = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.parentHash = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.sha3Uncles = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.logsBloom = null; + this.transactionsRoot = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.stateRoot = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.receiptsRoot = "0x88b221a282a64df608a820bae740425e5f439d1c"; + this.miner = null; + + this.difficulty = "0x0"; + this.totalDifficulty = "0x0"; + this.cumulativeDifficulty = "0x0"; + + this.extraData = "0x"; + this.size = toQuantityJsonHex(234); + this.gasLimit = toQuantityJsonHex(1233); + this.gasUsed = toQuantityJsonHex(12); + this.timestamp = toQuantityJsonHex(timestamp); + + this.transactions = Collections.unmodifiableList(transactions); + this.uncles = Collections.unmodifiableList(uncles); + + } +} diff --git a/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java b/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java new file mode 100644 index 00000000..4da87bf4 --- /dev/null +++ b/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java @@ -0,0 +1,53 @@ +package io.xdag.rpc.dto; + +import io.xdag.core.Block; + +import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; +import static io.xdag.rpc.utils.TypeConverter.toUnformattedJsonHex; +import static io.xdag.utils.BytesUtils.EMPTY_BYTE_ARRAY; + +public class ETHTransactionReceiptDTO { + + public static final int BLOOM_BYTES = 256; + private byte[] data = new byte[BLOOM_BYTES]; + protected static final byte[] FAILED_STATUS = EMPTY_BYTE_ARRAY; + protected static final byte[] PENDING_STATUS = new byte[]{0x02}; + protected static final byte[] SUCCESS_STATUS = new byte[]{0x01}; + + + private String transactionHash; // hash of the transaction. + private String transactionIndex; // integer of the transactions index position in the block. + private String blockHash; // hash of the block where this transaction was in. + private String blockNumber; // block number where this transaction was in. + private String cumulativeGasUsed; // The total amount of gas used when this transaction was executed in the block. + private String gasUsed; // The amount of gas used by this specific transaction alone. + private String contractAddress; // The contract address created, if the transaction was a contract creation, otherwise null . + private String from; // address of the sender. + private String to; // address of the receiver. null when it's a contract creation transaction. + private String status; // either 1 (success) or 0 (failure) + + // TODO : ignore + private String[] logs; // Array of log objects, which this transaction generated. + private String logsBloom; // Bloom filter for light clients to quickly retrieve related logs. + + public ETHTransactionReceiptDTO(Block block) { + + status = toQuantityJsonHex(SUCCESS_STATUS); + + blockHash = toUnformattedJsonHex(block.getHash()); + blockNumber = toQuantityJsonHex(19); + + + cumulativeGasUsed = toQuantityJsonHex(123); + from = "0x88b221a282a64df608a820bae740425e5f439d1c"; + gasUsed = toQuantityJsonHex(123); + + logs = new String[0]; + + to = "0x88b221a282a64df608a820bae740425e5f439d1c"; + transactionHash = "0x647edff965606eb655103f6dee0c3b2805a56c40b3592eb7a8d011552d1e1839"; + transactionIndex = toQuantityJsonHex(1); + logsBloom = toUnformattedJsonHex(data); + } + +} diff --git a/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java new file mode 100644 index 00000000..378b0af3 --- /dev/null +++ b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java @@ -0,0 +1,92 @@ +//package io.xdag.rpc.dto; +// +//import io.xdag.core.Block; +// +//import static io.xdag.rpc.utils.TypeConverter.toUnformattedJsonHex; +// +//public class TransactionReceiptDTO { +// private String transactionHash; // hash of the transaction. +// private String transactionIndex; // integer of the transactions index position in the block. +// private String blockHash; // hash of the block where this transaction was in. +// private String blockNumber; // block number where this transaction was in. +// private String cumulativeGasUsed; // The total amount of gas used when this transaction was executed in the block. +// private String gasUsed; // The amount of gas used by this specific transaction alone. +// private String contractAddress; // The contract address created, if the transaction was a contract creation, otherwise null . +// private String from; // address of the sender. +// private String to; // address of the receiver. null when it's a contract creation transaction. +// private String status; // either 1 (success) or 0 (failure) +// private String logsBloom; // Bloom filter for light clients to quickly retrieve related logs. +// +// public TransactionReceiptDTO(Block block) { +// TransactionReceipt receipt = txInfo.getReceipt(); +// +// status = toQuantityJsonHex(txInfo.getReceipt().getStatus()); +// blockHash = toUnformattedJsonHex(block.getHash()); +// blockNumber = toQuantityJsonHex(block.getNumber()); +// +// RskAddress contractAddress = receipt.getTransaction().getContractAddress(); +// if (contractAddress != null) { +// this.contractAddress = contractAddress.toJsonString(); +// } +// +// cumulativeGasUsed = toQuantityJsonHex(receipt.getCumulativeGas()); +// from = receipt.getTransaction().getSender().toJsonString(); +// gasUsed = toQuantityJsonHex(receipt.getGasUsed()); +// +// logs = new LogFilterElement[receipt.getLogInfoList().size()]; +// for (int i = 0; i < logs.length; i++) { +// LogInfo logInfo = receipt.getLogInfoList().get(i); +// logs[i] = new LogFilterElement(logInfo, block, txInfo.getIndex(), +// txInfo.getReceipt().getTransaction(), i); +// } +// +// to = receipt.getTransaction().getReceiveAddress().toJsonString(); +// transactionHash = receipt.getTransaction().getHash().toJsonString(); +// transactionIndex = toQuantityJsonHex(txInfo.getIndex()); +// logsBloom = toUnformattedJsonHex(txInfo.getReceipt().getBloomFilter().getData()); +// } +// +// public String getTransactionHash() { +// return transactionHash; +// } +// +// public String getTransactionIndex() { +// return transactionIndex; +// } +// +// public String getBlockHash() { +// return blockHash; +// } +// +// public String getBlockNumber() { +// return blockNumber; +// } +// +// public String getCumulativeGasUsed() { +// return cumulativeGasUsed; +// } +// +// public String getGasUsed() { +// return gasUsed; +// } +// +// public String getContractAddress() { +// return contractAddress; +// } +// +// public String getFrom() { +// return from; +// } +// +// public String getTo() { +// return to; +// } +// +// public String getStatus() { +// return status; +// } +// +// public String getLogsBloom() { +// return logsBloom; +// } +//} diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModule.java b/src/main/java/io/xdag/rpc/modules/eth/EthModule.java new file mode 100644 index 00000000..98f66fbc --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModule.java @@ -0,0 +1,45 @@ +package io.xdag.rpc.modules.eth; + +import io.xdag.rpc.Web3; +import io.xdag.rpc.utils.TypeConverter; + +public class EthModule implements EthModuleTransaction, EthModuleWallet{ + + + + private final byte chainId; + + public EthModule(byte chainId) { + this.chainId = chainId; + } + + + @Override + public String sendTransaction(Web3.CallArguments args) { + return null; + } + + @Override + public String sendRawTransaction(String rawData) { + return null; + } + + @Override + public String[] accounts() { + return new String[0]; + } + + @Override + public String sign(String addr, String data) { + return null; + } + + + public String chainId() { + return TypeConverter.toJsonHex(new byte[] { chainId }); + } + + public String getCode(String address, String blockId) { + return "0x"; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java b/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java new file mode 100644 index 00000000..8675c4ac --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java @@ -0,0 +1,28 @@ +/* + * This file is part of RskJ + * Copyright (C) 2018 RSK Labs Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package io.xdag.rpc.modules.eth; + + +import io.xdag.rpc.Web3; + +public interface EthModuleTransaction { + String sendTransaction(Web3.CallArguments args); + + String sendRawTransaction(String rawData); +} diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java b/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java new file mode 100644 index 00000000..9bfad1e3 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java @@ -0,0 +1,8 @@ +package io.xdag.rpc.modules.eth; + +public interface EthModuleWallet { + + String[] accounts(); + + String sign(String addr, String data); +} diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java index 8d0bc3a8..55a7276b 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java @@ -1,122 +1,129 @@ -//package io.xdag.rpc.modules.web3; -// -//import io.xdag.rpc.Web3; -// -//import java.math.BigInteger; -//import java.util.Map; -// -//public interface Web3EthModule { -// default String[] eth_accounts() { -// return getEthModule().accounts(); +package io.xdag.rpc.modules.web3; + +import io.xdag.rpc.dto.ETHBlockResultDTO; +import io.xdag.rpc.dto.ETHTransactionReceiptDTO; +import io.xdag.rpc.modules.eth.EthModule; + + +public interface Web3EthModule { + + default String[] eth_accounts() { + return getEthModule().accounts(); + } + + default String eth_sign(String addr, String data) { + return getEthModule().sign(addr, data); + } + +// default String eth_call(Web3.CallArguments args, String bnOrId) { +// return getEthModule().call(args, bnOrId); // } -// -// default String eth_sign(String addr, String data) { -// return getEthModule().sign(addr, data); + +// default String eth_estimateGas(Web3.CallArguments args) { +// return getEthModule().estimateGas(args); // } -// -//// default String eth_call(Web3.CallArguments args, String bnOrId) { -//// return getEthModule().call(args, bnOrId); -//// } -// -//// default String eth_estimateGas(Web3.CallArguments args) { -//// return getEthModule().estimateGas(args); -//// } -// -// -// -//// default Map eth_bridgeState() throws Exception { -//// return getEthModule().bridgeState(); -//// } -// -//// default String eth_chainId() { -//// return getEthModule().chainId(); -//// } -// -// EthModule getEthModule(); -// -// String eth_protocolVersion(); -// + + + +// default Map eth_bridgeState() throws Exception { +// return getEthModule().bridgeState(); +// } + + default String eth_chainId() { + return getEthModule().chainId(); + } + + EthModule getEthModule(); + + String eth_protocolVersion(); + // Object eth_syncing(); -// -// String eth_coinbase(); -// + + String eth_coinbase(); + // boolean eth_mining(); -// + // BigInteger eth_hashrate(); -// -// String eth_gasPrice(); -// -// String eth_blockNumber(); -// -// String eth_getBalance(String address, String block) throws Exception; -// -// String eth_getBalance(String address) throws Exception; -// -// String eth_getStorageAt(String address, String storageIdx, String blockId) throws Exception; -// -// String eth_getTransactionCount(String address, String blockId) throws Exception ; -// + + default String eth_gasPrice(){ + return "0x1"; + } + + String eth_blockNumber(); + + String eth_getBalance(String address, String block) throws Exception; + + String eth_getBalance(String address) throws Exception; + + String eth_getStorageAt(String address, String storageIdx, String blockId) throws Exception; + + default String eth_getTransactionCount(String address, String blockId) { + return "0x1"; + } + // String eth_getBlockTransactionCountByHash(String blockHash)throws Exception; -// + // String eth_getBlockTransactionCountByNumber(String bnOrId)throws Exception; -// + // String eth_getUncleCountByBlockHash(String blockHash)throws Exception; -// + // String eth_getUncleCountByBlockNumber(String bnOrId)throws Exception; -// -// default String eth_getCode(String address, String blockId) { -// return getEthModule().getCode(address, blockId); -// } -// -// default String eth_sendRawTransaction(String rawData) { -// return getEthModule().sendRawTransaction(rawData); -// } -// + + default String eth_getCode(String address, String blockId) { + return getEthModule().getCode(address, blockId); + } + + default String eth_sendRawTransaction(String rawData) { + return getEthModule().sendRawTransaction(rawData); + } + // default String eth_sendTransaction(Web3.CallArguments args) { // return getEthModule().sendTransaction(args); // } -// + // BlockResultDTO eth_getBlockByHash(String blockHash, Boolean fullTransactionObjects) throws Exception; -// -// BlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) throws Exception; -// -// TransactionResultDTO eth_getTransactionByHash(String transactionHash) throws Exception; -// -// TransactionResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) throws Exception; -// -// TransactionResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) throws Exception; -// -// TransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) throws Exception; -// + + ETHBlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) throws Exception; + +// BlockResultDTO eth_getTransactionByHash(String transactionHash) throws Exception; + +// BlockResultDTO eth_getTransactionByBlockHashAndIndex(String blockHash, String index) throws Exception; + +// BlockResultDTO eth_getTransactionByBlockNumberAndIndex(String bnOrId, String index) throws Exception; + + ETHTransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) throws Exception; + // BlockResultDTO eth_getUncleByBlockHashAndIndex(String blockHash, String uncleIdx) throws Exception; -// + // BlockResultDTO eth_getUncleByBlockNumberAndIndex(String blockId, String uncleIdx) throws Exception; -// + // String[] eth_getCompilers(); -// + // Map eth_compileLLL(String contract); -// + // Map eth_compileSerpent(String contract); -// + // Map eth_compileSolidity(String contract); -// + // String eth_newFilter(Web3.FilterRequest fr) throws Exception; -// + // String eth_newBlockFilter(); -// + // String eth_newPendingTransactionFilter(); -// + // boolean eth_uninstallFilter(String id); -// + // Object[] eth_getFilterChanges(String id); -// + // Object[] eth_getFilterLogs(String id); -// + // Object[] eth_getLogs(Web3.FilterRequest fr) throws Exception; -// + // BigInteger eth_netHashrate(); -// + // boolean eth_submitWork(String nonce, String header, String mince); -// + // boolean eth_submitHashrate(String hashrate, String id); -//} +} + + diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java new file mode 100644 index 00000000..147b8af7 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java @@ -0,0 +1,69 @@ +package io.xdag.rpc.modules.web3; + +import io.xdag.rpc.dto.ETHBlockResultDTO; +import io.xdag.rpc.dto.ETHTransactionReceiptDTO; +import io.xdag.rpc.modules.eth.EthModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; + +public class Web3EthModuleImpl implements Web3EthModule{ + private static final Logger logger = LoggerFactory.getLogger(Web3XdagModuleImpl.class); + + class SyncingResult { + public String currentBlock; + public String highestBlock; + } + + private final EthModule ethModule; + + public Web3EthModuleImpl(EthModule ethModule) { + this.ethModule = ethModule; + } + + @Override + public EthModule getEthModule() { + return ethModule; + } + + @Override + public String eth_protocolVersion() { + return Integer.toString(1); + } + + @Override + public String eth_coinbase() { + return "0x88b221a282a64df608a820bae740425e5f439d1c"; + } + + @Override + public String eth_blockNumber() { + return toQuantityJsonHex(12); + } + + @Override + public String eth_getBalance(String address, String block) throws Exception { + return toQuantityJsonHex(1000); + } + + @Override + public String eth_getBalance(String address) throws Exception { + return toQuantityJsonHex(2000); + } + + @Override + public String eth_getStorageAt(String address, String storageIdx, String blockId) throws Exception { + return "0x0"; + } + + @Override + public ETHBlockResultDTO eth_getBlockByNumber(String bnOrId, Boolean fullTransactionObjects) throws Exception { + return null; + } + + @Override + public ETHTransactionReceiptDTO eth_getTransactionReceipt(String transactionHash) throws Exception { + return null; + } +} diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java index 35526b9d..dd95af96 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java @@ -34,8 +34,8 @@ class SyncingResult { private final XdagModule xdagModule; private final Kernel kernel; - public Web3XdagModuleImpl(Blockchain blockchain, XdagModule xdagModule, Kernel kernel) { - this.blockchain = blockchain; + public Web3XdagModuleImpl(XdagModule xdagModule, Kernel kernel) { + this.blockchain = kernel.getBlockchain(); this.xdagModule = xdagModule; this.kernel = kernel; } diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java index 62c3096e..55a6ea30 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java @@ -1,9 +1,11 @@ package io.xdag.rpc.modules.xdag; -import io.xdag.config.Constants; +import io.xdag.core.Block; +import io.xdag.core.Blockchain; +import io.xdag.core.ImportResult; +import io.xdag.core.XdagBlock; import io.xdag.rpc.Web3; import io.xdag.rpc.utils.TypeConverter; -import io.xdag.wallet.Wallet; import org.bouncycastle.util.encoders.Hex; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,8 +15,14 @@ public class XdagModuleTransactionBase implements XdagModuleTransaction{ protected static final Logger logger = LoggerFactory.getLogger(XdagModuleTransactionBase.class); + private final Blockchain blockchain; + public XdagModuleTransactionBase(Blockchain blockchain) { + + this.blockchain = blockchain; + } + @Override public synchronized String sendTransaction(Web3.CallArguments args) { @@ -35,9 +43,15 @@ public synchronized String sendTransaction(Web3.CallArguments args) { public String sendRawTransaction(String rawData) { // 1. build transaction - // 2. try to add blockchain - - return null; + System.out.println(rawData); + Block block = new Block(new XdagBlock(Hex.decode(rawData))); + ImportResult result = blockchain.tryToConnect(block); + System.out.println(result); + if (!result.isLegal()) { + return "0x"; + } else { + return result.toString(); + } } } diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java index 9e3ffc5d..c22195bc 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java @@ -1,5 +1,6 @@ package io.xdag.rpc.modules.xdag; +import io.xdag.core.Blockchain; import io.xdag.rpc.Web3; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -10,6 +11,10 @@ public class XdagModuleTransactionDisabled extends XdagModuleTransactionBase{ private static final Logger logger = LoggerFactory.getLogger(XdagModuleTransactionDisabled.class); + public XdagModuleTransactionDisabled(Blockchain blockchain) { + super(blockchain); + } + @Override public String sendTransaction(Web3.CallArguments args) { logger.debug("xdag_sendTransaction({}): {}", args, null); diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java new file mode 100644 index 00000000..614e2d14 --- /dev/null +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java @@ -0,0 +1,16 @@ +package io.xdag.rpc.modules.xdag; + +import io.xdag.core.Blockchain; + +public class XdagModuleTransactionEnabled extends XdagModuleTransactionBase{ + + public XdagModuleTransactionEnabled(Blockchain blockchain) { + super(blockchain); + } + + @Override + public String sendRawTransaction(String rawData) { + String result = super.sendRawTransaction(rawData); + return result; + } +} diff --git a/src/main/resources/xdag-testnet.config b/src/main/resources/xdag-testnet.config index dcb29f9e..f6c08249 100644 --- a/src/main/resources/xdag-testnet.config +++ b/src/main/resources/xdag-testnet.config @@ -33,60 +33,5 @@ password = root whiteIPs = -modules = [ - { - name: "eth", - version: "1.0", - enabled: "true", - }, - { - name: "net", - version: "1.0", - enabled: "true", - }, - { - name: "rpc", - version: "1.0", - enabled: "true", - }, - { - name: "web3", - version: "1.0", - enabled: "true", - }, - { - name: "evm", - version: "1.0", - enabled: "true" - }, - { - name: "sco", - version: "1.0", - enabled: "true", - }, - { - name: "txpool", - version: "1.0", - enabled: "true", - }, - { - name: "personal", - version: "1.0", - enabled: "true" - }, - { - name: "debug", - version: "1.0", - enabled: "true" - }, - { - name: "trace", - version: "1.0", - enabled: "true" - }, - { - name: "rsk", - version: "1.0", - enabled: "true" - } - ] +isRPCEnabled = true + diff --git a/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java b/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java new file mode 100644 index 00000000..b6f14220 --- /dev/null +++ b/src/test/java/io/xdag/rpc/Web3XdagModuleTest.java @@ -0,0 +1,90 @@ +package io.xdag.rpc; + +import io.xdag.Kernel; +import io.xdag.config.Config; +import io.xdag.config.DevnetConfig; +import io.xdag.core.Blockchain; +import io.xdag.crypto.ECKeyPair; +import io.xdag.crypto.SampleKeys; +import io.xdag.crypto.jni.Native; +import io.xdag.db.DatabaseFactory; +import io.xdag.db.DatabaseName; +import io.xdag.db.rocksdb.RocksdbFactory; +import io.xdag.db.store.BlockStore; +import io.xdag.db.store.OrphanPool; +import io.xdag.rpc.modules.web3.Web3XdagModule; +import io.xdag.rpc.modules.web3.Web3XdagModuleImpl; +import io.xdag.rpc.modules.xdag.XdagModule; +import io.xdag.rpc.modules.xdag.XdagModuleTransactionEnabled; +import io.xdag.rpc.modules.xdag.XdagModuleWalletDisabled; +import io.xdag.utils.Numeric; +import io.xdag.wallet.Wallet; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.math.BigInteger; +import java.util.Collections; + +public class Web3XdagModuleTest { + + @Rule + public TemporaryFolder root = new TemporaryFolder(); + + Config config = new DevnetConfig(); + Wallet wallet; + String pwd; + Kernel kernel; + DatabaseFactory dbFactory; + + BigInteger private_1 = new BigInteger("c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", 16); + BigInteger private_2 = new BigInteger("10a55f0c18c46873ddbf9f15eddfc06f10953c601fd144474131199e04148046", 16); + + @Before + public void setUp() throws Exception { + config.getNodeSpec().setStoreDir(root.newFolder().getAbsolutePath()); + config.getNodeSpec().setStoreBackupDir(root.newFolder().getAbsolutePath()); + + Native.init(config); + if (Native.dnet_crypt_init() < 0) { + throw new Exception("dnet crypt init failed"); + } + pwd = "password"; + wallet = new Wallet(config); + wallet.unlock(pwd); + ECKeyPair key = ECKeyPair.create(Numeric.toBigInt(SampleKeys.PRIVATE_KEY_STRING)); + wallet.setAccounts(Collections.singletonList(key)); + wallet.flush(); + + kernel = new Kernel(config); + dbFactory = new RocksdbFactory(config); + + BlockStore blockStore = new BlockStore( + dbFactory.getDB(DatabaseName.INDEX), + dbFactory.getDB(DatabaseName.TIME), + dbFactory.getDB(DatabaseName.BLOCK)); + + blockStore.reset(); + OrphanPool orphanPool = new OrphanPool(dbFactory.getDB(DatabaseName.ORPHANIND)); + orphanPool.reset(); + + kernel.setBlockStore(blockStore); + kernel.setOrphanPool(orphanPool); + kernel.setWallet(wallet); + } + + @Test + public void syncingTest() { + + XdagModule xdagModule = new XdagModule((byte) 0x1,new XdagModuleWalletDisabled(),new XdagModuleTransactionEnabled(kernel.getBlockchain())); + Web3XdagModule web3XdagModule = createWeb3XdagModule(kernel,xdagModule); + + + } + + private Web3XdagModule createWeb3XdagModule(Kernel kernel,XdagModule module) { + + return new Web3XdagModuleImpl(module,kernel); + } +} diff --git a/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java b/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java new file mode 100644 index 00000000..960bd321 --- /dev/null +++ b/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java @@ -0,0 +1,30 @@ +package io.xdag.rpc.modules; + +import io.xdag.rpc.modules.xdag.XdagModule; +import io.xdag.rpc.modules.xdag.XdagModuleTransaction; +import io.xdag.rpc.modules.xdag.XdagModuleWallet; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + + +public class XdagModuleTest { + + @Test + public void chainId() { + XdagModule xdagModule = new XdagModule( + (byte) 0x21, + mock(XdagModuleWallet.class), + mock(XdagModuleTransaction.class) + + ); + assertEquals("0x21", xdagModule.chainId()); + } + + @Test + public void sendRawTransaction() { + + } +} diff --git a/src/test/java/io/xdag/rpc/netty/Web3HttpServerTest.java b/src/test/java/io/xdag/rpc/netty/Web3HttpServerTest.java new file mode 100644 index 00000000..6331d489 --- /dev/null +++ b/src/test/java/io/xdag/rpc/netty/Web3HttpServerTest.java @@ -0,0 +1,172 @@ +package io.xdag.rpc.netty; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.xdag.rpc.Web3; +import io.xdag.rpc.cors.CorsConfiguration; +import io.xdag.rpc.modules.ModuleDescription; +import okhttp3.*; +import org.junit.Ignore; +import org.junit.Test; +import org.mockito.Mockito; + +import javax.net.ssl.*; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URL; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.*; + +import static org.junit.Assert.assertEquals; + +public class Web3HttpServerTest { + public static final String APPLICATION_JSON = "application/json"; + private static JsonNodeFactory JSON_NODE_FACTORY = JsonNodeFactory.instance; + private static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @Test + public void smokeTestUsingJsonContentType() throws Exception { + smokeTest(APPLICATION_JSON); + } + +// @Test @Ignore("fix okhttp problem with charset/gzip") +// public void smokeTestUsingJsonWithCharsetContentType() throws Exception { +// smokeTest("application/json; charset: utf-8"); +// } +// +// @Test @Ignore("fix okhttp problem with charset/gzip") +// public void smokeTestUsingJsonRpcWithCharsetContentType() throws Exception { +// smokeTest("application/json-rpc; charset: utf-8"); +// } + + @Test + public void smokeTestUsingJsonRpcContentType() throws Exception { + smokeTest("application/json-rpc"); + } + + @Test(expected = IOException.class) + public void smokeTestUsingInvalidContentType() throws Exception { + smokeTest("text/plain"); + } + + @Test + public void smokeTestUsingValidHost() throws Exception { + smokeTest(APPLICATION_JSON, "localhost"); + } + + @Test(expected = IOException.class) + public void smokeTestUsingInvalidHost() throws Exception { + smokeTest(APPLICATION_JSON, "evil.com"); + } + + @Test + public void smokeTestUsingValidHostAndHostName() throws Exception { + String domain = "www.google.com"; + List rpcHost = new ArrayList<>(); + rpcHost.add(domain); + smokeTest(APPLICATION_JSON, domain, InetAddress.getByName(domain), rpcHost); + } + + @Test(expected = IOException.class) + public void smokeTestUsingInvalidHostAndHostName() throws Exception { + InetAddress google = InetAddress.getByName("www.google.com"); + smokeTest(APPLICATION_JSON, google.getHostAddress(), google, new ArrayList<>()); + } + + + private void smokeTest(String contentType, String host) throws Exception { + smokeTest(contentType, host, InetAddress.getLoopbackAddress(), new ArrayList<>()); + } + + private void smokeTest(String contentType, String host, InetAddress rpcAddress, List rpcHost) throws Exception { + Web3 web3Mock = Mockito.mock(Web3.class); + String mockResult = "output"; + Mockito.when(web3Mock.web3_sha3(Mockito.anyString())).thenReturn(mockResult); + CorsConfiguration mockCorsConfiguration = Mockito.mock(CorsConfiguration.class); + Mockito.when(mockCorsConfiguration.hasHeader()).thenReturn(true); + Mockito.when(mockCorsConfiguration.getHeader()).thenReturn("*"); + + int randomPort = 9999;//new ServerSocket(0).getLocalPort(); + + List filteredModules = Collections.singletonList(new ModuleDescription("web3", "1.0", true, Collections.emptyList(), Collections.emptyList())); + JsonRpcWeb3FilterHandler filterHandler = new JsonRpcWeb3FilterHandler("*", rpcAddress, rpcHost); + JsonRpcWeb3ServerHandler serverHandler = new JsonRpcWeb3ServerHandler(web3Mock, filteredModules); + Web3HttpServer server = new Web3HttpServer(InetAddress.getLoopbackAddress(), randomPort, 0, Boolean.TRUE, mockCorsConfiguration, filterHandler, serverHandler); + server.start(); + try { + Response response = sendJsonRpcMessage(randomPort, contentType, host); + JsonNode jsonRpcResponse = OBJECT_MAPPER.readTree(response.body().string()); + + assertEquals(response.code(), HttpResponseStatus.OK.code()); + assertEquals(jsonRpcResponse.at("/result").asText(), mockResult); + } finally { + server.stop(); + } + } + + private void smokeTest(String contentType) throws Exception { + smokeTest(contentType, "127.0.0.1"); + } + + private Response sendJsonRpcMessage(int port, String contentType, String host) throws IOException { + Map jsonRpcRequestProperties = new HashMap<>(); + jsonRpcRequestProperties.put("jsonrpc", JSON_NODE_FACTORY.textNode("2.0")); + jsonRpcRequestProperties.put("id", JSON_NODE_FACTORY.numberNode(13)); + jsonRpcRequestProperties.put("method", JSON_NODE_FACTORY.textNode("web3_sha3")); + jsonRpcRequestProperties.put("params", JSON_NODE_FACTORY.arrayNode().add("value")); + + RequestBody requestBody = RequestBody.create(MediaType.parse(contentType), JSON_NODE_FACTORY.objectNode() + .setAll(jsonRpcRequestProperties).toString()); + URL url = new URL("http", "localhost", port, "/"); + Request request = new Request.Builder().url(url) + .addHeader("Host", host) +// .addHeader("Accept-Encoding", "identity") + .post(requestBody).build(); + return getUnsafeOkHttpClient().newCall(request).execute(); + } + + private static OkHttpClient getUnsafeOkHttpClient() { + try { + // Create a trust manager that does not validate certificate chains + final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, + String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, + String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + }; + // Install the all-trusting trust manager + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + // Create an ssl socket factory with our all-trusting manager + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + + return new OkHttpClient.Builder() + .sslSocketFactory(sslSocketFactory,(X509TrustManager)trustAllCerts[0]) + .hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }) + .build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/io/xdag/rpc/netty/Web3WebSocketServerTest.java b/src/test/java/io/xdag/rpc/netty/Web3WebSocketServerTest.java new file mode 100644 index 00000000..1aecd7e5 --- /dev/null +++ b/src/test/java/io/xdag/rpc/netty/Web3WebSocketServerTest.java @@ -0,0 +1,159 @@ +package io.xdag.rpc.netty; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import io.xdag.rpc.Web3; +import io.xdag.rpc.modules.ModuleDescription; +import io.xdag.rpc.serialize.JacksonBasedRpcSerializer; +import lombok.SneakyThrows; +import okhttp3.*; +import okio.Buffer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static io.xdag.rpc.netty.Web3HttpServerTest.APPLICATION_JSON; +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.refEq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class Web3WebSocketServerTest { + private static JsonNodeFactory JSON_NODE_FACTORY = JsonNodeFactory.instance; + private static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + private ExecutorService wsExecutor; + + @Before + public void setup() { + wsExecutor = Executors.newSingleThreadExecutor(); + } + + @Test + public void smokeTest() throws Exception { + Web3 web3Mock = mock(Web3.class); + String mockResult = "output"; + when(web3Mock.web3_sha3(anyString())).thenReturn(mockResult); + + int randomPort = 9998;//new ServerSocket(0).getLocalPort(); + + List filteredModules = Collections.singletonList(new ModuleDescription("web3", "1.0", true, Collections.emptyList(), Collections.emptyList())); + XdagJsonRpcHandler handler = new XdagJsonRpcHandler( new JacksonBasedRpcSerializer()); + JsonRpcWeb3ServerHandler serverHandler = new JsonRpcWeb3ServerHandler(web3Mock, filteredModules); + + Web3WebSocketServer websocketServer = new Web3WebSocketServer(InetAddress.getLoopbackAddress(), randomPort, handler, serverHandler); + websocketServer.start(); + + OkHttpClient wsClient = new OkHttpClient(); + Request wsRequest = new Request.Builder().url("ws://localhost:"+randomPort+"/websocket").build(); + + CountDownLatch wsAsyncResultLatch = new CountDownLatch(1); + CountDownLatch wsAsyncCloseLatch = new CountDownLatch(1); + AtomicReference failureReference = new AtomicReference<>(); + + wsClient.newWebSocket(wsRequest,new WebSocketListener() { + + private WebSocket webSocket; + + @Override + public void onOpen(WebSocket webSocket, Response response) { + wsExecutor.submit(() -> { + Buffer buffer = new Buffer(); + try { + RequestBody.create( getJsonRpcDummyMessage(),MediaType.get(APPLICATION_JSON)).writeTo(buffer); + } catch (IOException e) { + e.printStackTrace(); + } + String req = buffer.readUtf8(); + try { + this.webSocket = webSocket; + this.webSocket.send(req); + this.webSocket.close(1000, null); + } catch (Throwable e) { + failureReference.set(e); + } + }); + } + + @Override + public void onFailure(@NotNull WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) { + failureReference.set(t); + } + + @SneakyThrows + @Override + public void onMessage(@NotNull WebSocket webSocket, @NotNull String bytes) { + JsonNode jsonRpcResponse = OBJECT_MAPPER.readTree(bytes); + assertEquals(jsonRpcResponse.at("/result").asText(),mockResult); + wsAsyncResultLatch.countDown(); + } + +// @Override +// public void onClosed(@NotNull WebSocket webSocket, int code, @NotNull String reason) { +// wsAsyncCloseLatch.countDown(); +// } + + @Override + public void onClosing(@NotNull WebSocket webSocket, int code, @NotNull String reason) { + wsAsyncCloseLatch.countDown(); + } + }); + + + if (!wsAsyncResultLatch.await(10, TimeUnit.SECONDS)) { + fail("Result timed out"); + } + + if (!wsAsyncCloseLatch.await(10, TimeUnit.SECONDS)) { + fail("Close timed out"); + } + + websocketServer.stop(); + + Throwable failure = failureReference.get(); + if (failure != null) { + failure.printStackTrace(); + fail(failure.getMessage()); + } + } + + @After + public void tearDown() { + wsExecutor.shutdown(); + } + + private byte[] getJsonRpcDummyMessage() { + Map jsonRpcRequestProperties = new HashMap<>(); + jsonRpcRequestProperties.put("jsonrpc", JSON_NODE_FACTORY.textNode("2.0")); + jsonRpcRequestProperties.put("id", JSON_NODE_FACTORY.numberNode(13)); + jsonRpcRequestProperties.put("method", JSON_NODE_FACTORY.textNode("web3_sha3")); + jsonRpcRequestProperties.put("params", JSON_NODE_FACTORY.arrayNode().add("value")); + + byte[] request = new byte[0]; + try { + request = OBJECT_MAPPER.writeValueAsBytes(OBJECT_MAPPER.treeToValue( + JSON_NODE_FACTORY.objectNode().setAll(jsonRpcRequestProperties), Object.class)); + } catch (JsonProcessingException e) { + fail(e.getMessage()); + } + return request; + + } +} From 5ff08212e4aed1079111ce5ff1507bded593689f Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 16:24:11 +0800 Subject: [PATCH 06/11] merge develop --- docs/README_zh.md | 8 +- ...ration_RandomX_Algorithm_Environment_zh.md | 1 + docs/XDAGJ_Cli_Wallet_eng.md | 25 +- docs/{ => img}/Open_the_security_group.png | Bin docs/{ => img}/RandomX_first.png | Bin docs/{ => img}/RandomX_three.png | Bin docs/{ => img}/RandomX_two.png | Bin pom.xml | 192 ++++-- script/xdag.bat | 12 + script/xdag.sh | 2 +- src/main/java/io/xdag/Kernel.java | 11 +- src/main/java/io/xdag/Launcher.java | 3 - src/main/java/io/xdag/cli/Commands.java | 15 +- src/main/java/io/xdag/cli/Shell.java | 12 +- src/main/java/io/xdag/cli/XdagCli.java | 32 +- src/main/java/io/xdag/cli/XdagOption.java | 2 - .../java/io/xdag/config/AbstractConfig.java | 25 +- .../java/io/xdag/config/RandomXConstants.java | 2 +- .../java/io/xdag/config/TestnetConfig.java | 2 +- .../java/io/xdag/config/spec/NodeSpec.java | 3 +- .../java/io/xdag/consensus/SyncManager.java | 57 +- src/main/java/io/xdag/consensus/XdagPow.java | 7 +- src/main/java/io/xdag/consensus/XdagSync.java | 7 +- src/main/java/io/xdag/core/BlockWrapper.java | 2 +- .../java/io/xdag/core/BlockchainImpl.java | 76 ++- .../xdag/discovery/DiscoveryController.java | 543 ----------------- .../io/xdag/discovery/PeerDiscoveryEvent.java | 61 -- .../io/xdag/discovery/RetryDelayFunction.java | 33 -- .../java/io/xdag/discovery/data/Packet.java | 179 ------ .../io/xdag/discovery/data/PacketData.java | 42 -- .../io/xdag/discovery/data/PacketType.java | 79 --- .../message/FindNeighborsPacketData.java | 84 --- .../message/NeighborsPacketData.java | 90 --- .../discovery/message/PingPacketData.java | 109 ---- .../discovery/message/PongPacketData.java | 94 --- .../java/io/xdag/discovery/peers/Bucket.java | 109 ---- .../io/xdag/discovery/peers/DefaultPeer.java | 198 ------- .../xdag/discovery/peers/DefaultPeerId.java | 66 --- .../xdag/discovery/peers/DiscoveryPeer.java | 122 ---- .../io/xdag/discovery/peers/Endpoint.java | 174 ------ .../java/io/xdag/discovery/peers/Peer.java | 57 -- .../xdag/discovery/peers/PeerBlacklist.java | 89 --- .../peers/PeerDistanceCalculator.java | 61 -- .../java/io/xdag/discovery/peers/PeerId.java | 41 -- .../io/xdag/discovery/peers/PeerTable.java | 257 -------- src/main/java/io/xdag/libp2p/P2PNetwork.java | 75 --- .../xdag/libp2p/RPCHandler/BlockHandler.java | 130 ----- .../io/xdag/libp2p/RPCHandler/RPCHandler.java | 339 ----------- .../io/xdag/libp2p/RPCHandler/XHandler.java | 71 --- .../xdag/libp2p/manager/ChannelManager.java | 127 ---- .../xdag/libp2p/message/MessageQueueLib.java | 135 ----- src/main/java/io/xdag/net/Channel.java | 46 ++ src/main/java/io/xdag/net/XdagChannel.java | 20 +- .../net/discovery/DiscoveryController.java | 46 ++ .../io/xdag/net/discovery/DiscoveryPeer.java | 47 ++ .../xdag/net/discovery/DiscoveryService.java | 24 + .../discovery/discv5/DiscV5ServiceImpl.java | 76 +++ .../discovery/discv5/NodeRecordConverter.java | 25 + .../noop/NoOpDiscoveryServiceImpl.java | 40 ++ src/main/java/io/xdag/net/handler/Xdag03.java | 49 +- .../io/xdag/net/handler/XdagBlockHandler.java | 30 +- .../java/io/xdag/net/handler/XdagHandler.java | 4 +- .../DiscoveryPeerToMultiaddrConverter.java | 38 ++ .../xdag/{ => net}/libp2p/Libp2pChannel.java | 96 ++- .../xdag/{ => net}/libp2p/Libp2pNetwork.java | 95 +-- .../libp2p/P2PNetwork.java} | 28 +- .../{ => net}/libp2p/RPCHandler/Firewall.java | 2 +- .../net/libp2p/RPCHandler/NonHandler.java} | 40 +- .../net/libp2p/RPCHandler/RPCHandler.java | 108 ++++ .../{ => net}/libp2p/manager/PeerManager.java | 10 +- .../libp2p/peer/DiscoveryPeerConverter.java | 47 ++ .../{ => net}/libp2p/peer/LibP2PNodeId.java | 2 +- .../{ => net}/libp2p/peer/Libp2pNode.java | 2 +- .../io/xdag/{ => net}/libp2p/peer/NodeId.java | 2 +- .../io/xdag/{ => net}/libp2p/peer/Peer.java | 4 +- .../{ => net}/libp2p/peer/PeerAddress.java | 2 +- .../xdag/net/manager/XdagChannelManager.java | 23 +- .../io/xdag/net/message/MessageQueue.java | 6 +- .../xdag/{ => net}/nat/NatConfiguration.java | 2 +- .../io/xdag/{ => net}/nat/NatManager.java | 2 +- .../java/io/xdag/{ => net}/nat/NatMethod.java | 2 +- .../io/xdag/{ => net}/nat/NatPortMapping.java | 2 +- .../io/xdag/{ => net}/nat/NatService.java | 5 +- .../io/xdag/{ => net}/nat/NatServiceType.java | 2 +- .../xdag/{ => net}/nat/NetworkProtocol.java | 2 +- .../{ => net}/nat/OkHttpStreamClient.java | 2 +- .../io/xdag/{ => net}/nat/UpnpClient.java | 5 +- .../xdag/{ => net}/nat/XdagGetExternalIP.java | 6 +- .../nat/XdagNatServiceConfiguration.java | 2 +- .../{ => net}/nat/XdagPortMappingAdd.java | 2 +- .../{ => net}/nat/XdagPortMappingDelete.java | 2 +- .../{ => net}/nat/XdagRegistryListener.java | 2 +- .../java/io/xdag/net/node/NodeManager.java | 75 +-- src/main/java/io/xdag/rpc/Web3.java | 23 + src/main/java/io/xdag/rpc/Web3Impl.java | 29 + .../io/xdag/rpc/cors/CorsConfiguration.java | 23 + .../io/xdag/rpc/cors/OriginValidator.java | 23 + .../java/io/xdag/rpc/dto/BlockResultDTO.java | 25 +- .../io/xdag/rpc/dto/ETHBlockResultDTO.java | 23 + .../rpc/dto/ETHTransactionReceiptDTO.java | 23 + src/main/java/io/xdag/rpc/dto/StatusDTO.java | 46 +- .../xdag/rpc/dto/TransactionReceiptDTO.java | 121 +--- .../xdag/rpc/exception/XdagErrorResolver.java | 23 + .../XdagJsonRpcRequestException.java | 23 + .../xdag/rpc/filter/JsonRpcMethodFilter.java | 23 + .../rpc/jsonrpc/JsonRpcBooleanResult.java | 23 + .../io/xdag/rpc/jsonrpc/JsonRpcError.java | 23 + .../rpc/jsonrpc/JsonRpcErrorResponse.java | 23 + .../jsonrpc/JsonRpcIdentifiableMessage.java | 23 + .../rpc/jsonrpc/JsonRpcInternalError.java | 23 + .../io/xdag/rpc/jsonrpc/JsonRpcMessage.java | 25 +- .../io/xdag/rpc/jsonrpc/JsonRpcRequest.java | 23 + .../io/xdag/rpc/jsonrpc/JsonRpcResult.java | 23 + .../rpc/jsonrpc/JsonRpcResultOrError.java | 23 + .../rpc/jsonrpc/JsonRpcResultResponse.java | 23 + .../io/xdag/rpc/jsonrpc/JsonRpcVersion.java | 23 + .../java/io/xdag/rpc/jsonrpc/JsonUtils.java | 23 + .../xdag/rpc/modules/ModuleDescription.java | 23 + .../xdag/rpc/modules/XdagJsonRpcMethod.java | 23 + .../xdag/rpc/modules/XdagJsonRpcRequest.java | 23 + .../modules/XdagJsonRpcRequestVisitor.java | 23 + .../xdag/rpc/modules/debug/DebugModule.java | 31 +- .../rpc/modules/debug/DebugModuleImpl.java | 31 +- .../io/xdag/rpc/modules/eth/EthModule.java | 23 + .../rpc/modules/eth/EthModuleTransaction.java | 31 +- .../xdag/rpc/modules/eth/EthModuleWallet.java | 23 + .../xdag/rpc/modules/web3/Web3EthModule.java | 23 + .../rpc/modules/web3/Web3EthModuleImpl.java | 23 + .../xdag/rpc/modules/web3/Web3XdagModule.java | 25 + .../rpc/modules/web3/Web3XdagModuleImpl.java | 35 ++ .../io/xdag/rpc/modules/xdag/XdagModule.java | 23 + .../rpc/modules/xdag/XdagModuleChain.java | 23 + .../rpc/modules/xdag/XdagModuleChainBase.java | 23 + .../modules/xdag/XdagModuleTransaction.java | 23 + .../xdag/XdagModuleTransactionBase.java | 23 + .../xdag/XdagModuleTransactionDisabled.java | 23 + .../xdag/XdagModuleTransactionEnabled.java | 23 + .../rpc/modules/xdag/XdagModuleWallet.java | 23 + .../xdag/XdagModuleWalletDisabled.java | 23 + .../xdag/subscribe/SubscriptionId.java | 52 -- .../xdag/subscribe/XDAGSubscribeRequest.java | 47 -- .../subscribe/XDAGUnsubscribeRequest.java | 4 - .../xdag/subscribe/XdagSubscribeParams.java | 15 - .../XdagSubscribeParamsDeserializer.java | 60 -- .../subscribe/XdagSubscribeParamsVisitor.java | 19 - .../XdagSubscriptionNotificationDTO.java | 4 - .../rpc/netty/JsonRpcWeb3FilterHandler.java | 23 + .../rpc/netty/JsonRpcWeb3ServerHandler.java | 31 +- .../netty/Web3HttpMethodFilterHandler.java | 30 +- .../io/xdag/rpc/netty/Web3HttpServer.java | 23 + .../java/io/xdag/rpc/netty/Web3Result.java | 30 +- .../netty/Web3ResultHttpResponseHandler.java | 30 +- .../Web3ResultWebSocketResponseHandler.java | 30 +- .../xdag/rpc/netty/Web3WebSocketServer.java | 30 +- .../io/xdag/rpc/netty/XdagJsonRpcHandler.java | 23 + .../serialize/JacksonBasedRpcSerializer.java | 23 + .../xdag/rpc/serialize/JsonRpcSerializer.java | 23 + .../java/io/xdag/rpc/utils/HttpUtils.java | 23 + .../java/io/xdag/rpc/utils/TypeConverter.java | 23 + src/main/java/io/xdag/utils/BasicUtils.java | 11 +- src/main/java/io/xdag/utils/BytesUtils.java | 4 +- .../io/xdag/utils/MultiaddrPeerAddress.java | 6 +- .../java/io/xdag/utils/MultiaddrUtil.java | 17 +- src/main/java/io/xdag/utils/StringUtils.java | 10 +- .../BouncyCastleMessageDigestFactory.java | 39 -- .../MalformedRLPInputException.java | 32 - .../utils/discoveryutils/NetworkUtility.java | 77 --- .../PeerDiscoveryPacketDecodingException.java | 34 -- .../discoveryutils/PeerDiscoveryStatus.java | 51 -- .../utils/discoveryutils/Preconditions.java | 40 -- .../xdag/utils/discoveryutils/RLPInput.java | 86 --- .../utils/discoveryutils/Subscribers.java | 39 -- .../bytes/AbstractBytesValue.java | 158 ----- .../bytes/AbstractRLPOutput.java | 189 ------ .../bytes/ArrayWrappingBytes32.java | 70 --- .../bytes/ArrayWrappingBytesValue.java | 190 ------ .../utils/discoveryutils/bytes/Bytes32.java | 191 ------ .../discoveryutils/bytes/Bytes32Backed.java | 29 - .../utils/discoveryutils/bytes/Bytes32s.java | 131 ----- .../discoveryutils/bytes/BytesBacked.java | 29 - .../discoveryutils/bytes/BytesValue.java | 550 ------------------ .../bytes/BytesValueRLPOutput.java | 42 -- .../discoveryutils/bytes/BytesValues.java | 295 ---------- .../bytes/MutableArrayWrappingBytes32.java | 47 -- .../bytes/MutableArrayWrappingBytesValue.java | 77 --- .../MutableBufferWrappingBytesValue.java | 99 ---- .../MutableByteBufWrappingBytesValue.java | 99 ---- .../MutableByteBufferWrappingBytesValue.java | 130 ----- .../discoveryutils/bytes/MutableBytes32.java | 151 ----- .../bytes/MutableBytesValue.java | 260 --------- .../xdag/utils/discoveryutils/bytes/RLP.java | 232 -------- .../bytes/RLPDecodingHelpers.java | 209 ------- .../bytes/RLPEncodingHelpers.java | 110 ---- .../utils/discoveryutils/bytes/RLPOutput.java | 217 ------- .../discoveryutils/bytes/WrappingBytes32.java | 69 --- .../bytes/uint/AbstractRLPInput.java | 480 --------------- .../bytes/uint/AbstractUInt256Value.java | 196 ------- .../bytes/uint/BaseUInt256Value.java | 69 --- .../bytes/uint/BytesValueRLPInput.java | 87 --- .../uint/CorruptedRLPInputException.java | 31 - .../discoveryutils/bytes/uint/Counter.java | 97 --- .../bytes/uint/DefaultInt256.java | 81 --- .../bytes/uint/DefaultUInt256.java | 49 -- .../discoveryutils/bytes/uint/Int256.java | 57 -- .../bytes/uint/Int256Bytes.java | 95 --- .../bytes/uint/RLPException.java | 34 -- .../discoveryutils/bytes/uint/UInt256.java | 63 -- .../bytes/uint/UInt256Bytes.java | 429 -------------- .../bytes/uint/UInt256Value.java | 169 ------ .../discoveryutils/bytes/uint/UInt256s.java | 55 -- .../xdag/utils/discoveryutils/cryto/Hash.java | 60 -- src/main/java/io/xdag/wallet/OldWallet.java | 2 + src/main/java/io/xdag/wallet/WalletUtils.java | 2 + src/main/resources/xdag-mainnet.config | 2 + src/main/resources/xdag-testnet.config | 3 +- src/test/java/io/xdag/cli/XdagCliTest.java | 53 +- .../io/xdag/{ => net}/nat/NatManagerTest.java | 2 +- .../io/xdag/{ => net}/nat/NatServiceTest.java | 2 +- .../{ => net}/nat/NatServiceTypeTest.java | 2 +- .../io/xdag/{ => net}/nat/UpnpClientTest.java | 5 +- .../io/xdag/rpc/modules/XdagModuleTest.java | 1 - .../java/io/xdag/utils/BasicUtilsTest.java | 15 +- ...339b55796b3585127c180fd4cbc54612122cf.json | 1 - 223 files changed, 2487 insertions(+), 10331 deletions(-) rename docs/{ => img}/Open_the_security_group.png (100%) rename docs/{ => img}/RandomX_first.png (100%) rename docs/{ => img}/RandomX_three.png (100%) rename docs/{ => img}/RandomX_two.png (100%) create mode 100644 script/xdag.bat delete mode 100644 src/main/java/io/xdag/discovery/DiscoveryController.java delete mode 100644 src/main/java/io/xdag/discovery/PeerDiscoveryEvent.java delete mode 100644 src/main/java/io/xdag/discovery/RetryDelayFunction.java delete mode 100644 src/main/java/io/xdag/discovery/data/Packet.java delete mode 100644 src/main/java/io/xdag/discovery/data/PacketData.java delete mode 100644 src/main/java/io/xdag/discovery/data/PacketType.java delete mode 100644 src/main/java/io/xdag/discovery/message/FindNeighborsPacketData.java delete mode 100644 src/main/java/io/xdag/discovery/message/NeighborsPacketData.java delete mode 100644 src/main/java/io/xdag/discovery/message/PingPacketData.java delete mode 100644 src/main/java/io/xdag/discovery/message/PongPacketData.java delete mode 100755 src/main/java/io/xdag/discovery/peers/Bucket.java delete mode 100644 src/main/java/io/xdag/discovery/peers/DefaultPeer.java delete mode 100644 src/main/java/io/xdag/discovery/peers/DefaultPeerId.java delete mode 100755 src/main/java/io/xdag/discovery/peers/DiscoveryPeer.java delete mode 100755 src/main/java/io/xdag/discovery/peers/Endpoint.java delete mode 100644 src/main/java/io/xdag/discovery/peers/Peer.java delete mode 100644 src/main/java/io/xdag/discovery/peers/PeerBlacklist.java delete mode 100644 src/main/java/io/xdag/discovery/peers/PeerDistanceCalculator.java delete mode 100644 src/main/java/io/xdag/discovery/peers/PeerId.java delete mode 100755 src/main/java/io/xdag/discovery/peers/PeerTable.java delete mode 100644 src/main/java/io/xdag/libp2p/P2PNetwork.java delete mode 100644 src/main/java/io/xdag/libp2p/RPCHandler/BlockHandler.java delete mode 100644 src/main/java/io/xdag/libp2p/RPCHandler/RPCHandler.java delete mode 100644 src/main/java/io/xdag/libp2p/RPCHandler/XHandler.java delete mode 100644 src/main/java/io/xdag/libp2p/manager/ChannelManager.java delete mode 100755 src/main/java/io/xdag/libp2p/message/MessageQueueLib.java create mode 100644 src/main/java/io/xdag/net/Channel.java create mode 100644 src/main/java/io/xdag/net/discovery/DiscoveryController.java create mode 100644 src/main/java/io/xdag/net/discovery/DiscoveryPeer.java create mode 100644 src/main/java/io/xdag/net/discovery/DiscoveryService.java create mode 100644 src/main/java/io/xdag/net/discovery/discv5/DiscV5ServiceImpl.java create mode 100644 src/main/java/io/xdag/net/discovery/discv5/NodeRecordConverter.java create mode 100644 src/main/java/io/xdag/net/discovery/noop/NoOpDiscoveryServiceImpl.java create mode 100644 src/main/java/io/xdag/net/libp2p/DiscoveryPeerToMultiaddrConverter.java rename src/main/java/io/xdag/{ => net}/libp2p/Libp2pChannel.java (52%) rename src/main/java/io/xdag/{ => net}/libp2p/Libp2pNetwork.java (70%) rename src/main/java/io/xdag/{utils/discoveryutils/bytes/AbstractBytes32Backed.java => net/libp2p/P2PNetwork.java} (77%) rename src/main/java/io/xdag/{ => net}/libp2p/RPCHandler/Firewall.java (98%) rename src/{test/java/io/xdag/libp2p/HandlerTest.java => main/java/io/xdag/net/libp2p/RPCHandler/NonHandler.java} (79%) create mode 100644 src/main/java/io/xdag/net/libp2p/RPCHandler/RPCHandler.java rename src/main/java/io/xdag/{ => net}/libp2p/manager/PeerManager.java (95%) create mode 100644 src/main/java/io/xdag/net/libp2p/peer/DiscoveryPeerConverter.java rename src/main/java/io/xdag/{ => net}/libp2p/peer/LibP2PNodeId.java (97%) rename src/main/java/io/xdag/{ => net}/libp2p/peer/Libp2pNode.java (97%) rename src/main/java/io/xdag/{ => net}/libp2p/peer/NodeId.java (98%) rename src/main/java/io/xdag/{ => net}/libp2p/peer/Peer.java (95%) rename src/main/java/io/xdag/{ => net}/libp2p/peer/PeerAddress.java (98%) rename src/main/java/io/xdag/{ => net}/nat/NatConfiguration.java (98%) rename src/main/java/io/xdag/{ => net}/nat/NatManager.java (99%) rename src/main/java/io/xdag/{ => net}/nat/NatMethod.java (97%) rename src/main/java/io/xdag/{ => net}/nat/NatPortMapping.java (98%) rename src/main/java/io/xdag/{ => net}/nat/NatService.java (97%) rename src/main/java/io/xdag/{ => net}/nat/NatServiceType.java (98%) rename src/main/java/io/xdag/{ => net}/nat/NetworkProtocol.java (97%) rename src/main/java/io/xdag/{ => net}/nat/OkHttpStreamClient.java (99%) rename src/main/java/io/xdag/{ => net}/nat/UpnpClient.java (99%) rename src/main/java/io/xdag/{ => net}/nat/XdagGetExternalIP.java (99%) rename src/main/java/io/xdag/{ => net}/nat/XdagNatServiceConfiguration.java (99%) rename src/main/java/io/xdag/{ => net}/nat/XdagPortMappingAdd.java (99%) rename src/main/java/io/xdag/{ => net}/nat/XdagPortMappingDelete.java (99%) rename src/main/java/io/xdag/{ => net}/nat/XdagRegistryListener.java (99%) delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java delete mode 100644 src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/BouncyCastleMessageDigestFactory.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/MalformedRLPInputException.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/NetworkUtility.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryPacketDecodingException.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryStatus.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/Preconditions.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/RLPInput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/Subscribers.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractRLPOutput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytes32.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32Backed.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32s.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/BytesBacked.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValueRLPOutput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValues.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytes32.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBufferWrappingBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufWrappingBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufferWrappingBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytes32.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytesValue.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/RLP.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/RLPDecodingHelpers.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/RLPEncodingHelpers.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/RLPOutput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/WrappingBytes32.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractRLPInput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractUInt256Value.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BaseUInt256Value.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BytesValueRLPInput.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/CorruptedRLPInputException.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Counter.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultInt256.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultUInt256.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256Bytes.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/RLPException.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Bytes.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Value.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256s.java delete mode 100644 src/main/java/io/xdag/utils/discoveryutils/cryto/Hash.java rename src/test/java/io/xdag/{ => net}/nat/NatManagerTest.java (99%) rename src/test/java/io/xdag/{ => net}/nat/NatServiceTest.java (99%) rename src/test/java/io/xdag/{ => net}/nat/NatServiceTypeTest.java (98%) rename src/test/java/io/xdag/{ => net}/nat/UpnpClientTest.java (99%) delete mode 100644 src/test/resources/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json diff --git a/docs/README_zh.md b/docs/README_zh.md index e2a0f842..711440a1 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -35,11 +35,11 @@ XDAGJ教程可以让您快速加入并体验XDAGJ的钱包及挖矿功能,私 ## 发展 -XDAGJ已经具备了一个矿池基本的功能,后续的工作继续优化现有代码,提升系统的稳定性。及时吸纳优秀的区块链技术,不断为XDAG注入新鲜血液 +火星计划一方面规划XDAG未来的发展路径,凝聚社区力量,推动XDAG向新的高度演进;另一方面利用全球排名第一的Java编程语言完善XDAG生态体系,吸引开发者加入。 ### 火星计划 -火星计划优先解决社区关注的技术问题,期间研究有重大突破可灵活加入开发计划,最新阶段性计划如下: +四个阶段: #### 探索阶段:XDAGJ测试网上线(已上线,公测中) @@ -80,9 +80,9 @@ XDAGJ已经具备了一个矿池基本的功能,后续的工作继续优化现 - [ ] 开放智能合约,实现支持Solidity的EVM,兼容以太坊智能合约 -- [ ] 降低矿池门槛,逐步开放白名单从而实现完全中心化 +- [ ] 降低矿池门槛,逐步开放白名单从而实现完全去中心化 -#### 繁荣阶段:DAG & DeFi +#### 繁荣阶段:XDAGJ & DeFi - [ ] 跨链:兼容多种区块链系统接入,实现XDAG与其它链世界的互通 diff --git a/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md b/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md index 56cd5619..5abc4d5c 100644 --- a/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md +++ b/docs/Win10_Configuration_RandomX_Algorithm_Environment_zh.md @@ -40,3 +40,4 @@ pause ![RandomX_three](img/RandomX_three.png) + \ No newline at end of file diff --git a/docs/XDAGJ_Cli_Wallet_eng.md b/docs/XDAGJ_Cli_Wallet_eng.md index 8564b211..7fd40c4c 100644 --- a/docs/XDAGJ_Cli_Wallet_eng.md +++ b/docs/XDAGJ_Cli_Wallet_eng.md @@ -109,9 +109,12 @@ This command is used to convert the wallet.dat file generated by the old wallet ```shell xdager@localhost xdag_full_node % ./xdag.sh --convertoldwallet wallet.dat -PrivateKey:4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 - PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 -Old Wallet Converted Successfully! +Old wallet password: +Old wallet random: +PrivateKey:008f30bc86f42f55d8d64dd26a5428fc1e65f0616823153c084b43aad76cd97e04 + PublicKey:2cc759b26fe0cf8480607421511e399c8b500790a978785559c38b91a420b2e57115d4618c0e0765e2961a5afa15ac465ae2029bbf6960a3e2ece8de896a964e + Address:2f9113df1d55a8447c73759ec23afb5566e14d03 +Old Wallet Converted Successfully! ``` ### dumpprivatekey @@ -119,8 +122,8 @@ Old Wallet Converted Successfully! Dump the private key in hexadecimal string format. ```shell -xdager@localhost xdag_full_node % ./xdag.sh --dumpprivatekey 47af7c90483f95ff030f12458071d0528ac3c5d0 -Private:4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 +xdager@localhost xdag_full_node % ./xdag.sh --dumpprivatekey 2f9113df1d55a8447c73759ec23afb5566e14d03 +Private:008f30bc86f42f55d8d64dd26a5428fc1e65f0616823153c084b43aad76cd97e04 Private Dump Successfully! ``` @@ -129,9 +132,9 @@ Private Dump Successfully! Import the private key in hexadecimal string format. ```shell -xdager@localhost xdag_full_node % ./xdag.sh --importprivatekey 4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 -Address:47af7c90483f95ff030f12458071d0528ac3c5d0 -PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 +xdager@localhost xdag_full_node % ./xdag.sh --importprivatekey 008f30bc86f42f55d8d64dd26a5428fc1e65f0616823153c084b43aad76cd97e04 +Address:2f9113df1d55a8447c73759ec23afb5566e14d03 +PublicKey:2cc759b26fe0cf8480607421511e399c8b500790a978785559c38b91a420b2e57115d4618c0e0765e2961a5afa15ac465ae2029bbf6960a3e2ece8de896a964e Private Key Imported Successfully! ``` @@ -140,9 +143,9 @@ Private Key Imported Successfully! Use mnemonic phrase import to generate new HDWallet. ```shell -xdager@localhost xdag_full_node % ./xdag.sh --importprivatekey 4a7dc39ff17b8b48b42edf856a0cf956e29741b02da3f00fff60967d55cad907 -Address:47af7c90483f95ff030f12458071d0528ac3c5d0 -PublicKey:4b9e26714f33134572cce57d06edbb502fb819d524b66610976f25843749f123ee8f4beedd22ff5126e8d27a7abb7d64a54927c9bbfb5fc0d66777bc10f1a646 +xdager@localhost xdag_full_node % ./xdag.sh --importmnemonic "smoke that notice super program endless culture bubble trial pass annual rule" +New Address:89fc1798f2e39687f566db6c02838990206978be +PublicKey:0092909df115b0646f5f771a0505c9c55cc875aeea2a440b7dd11afbd54b350482749d7dba68d1bff96c19adb1a6e920be2e959a684a8ab7545a9a213d85dc4a57 HDWallet Mnemonic Imported Successfully! ``` diff --git a/docs/Open_the_security_group.png b/docs/img/Open_the_security_group.png similarity index 100% rename from docs/Open_the_security_group.png rename to docs/img/Open_the_security_group.png diff --git a/docs/RandomX_first.png b/docs/img/RandomX_first.png similarity index 100% rename from docs/RandomX_first.png rename to docs/img/RandomX_first.png diff --git a/docs/RandomX_three.png b/docs/img/RandomX_three.png similarity index 100% rename from docs/RandomX_three.png rename to docs/img/RandomX_three.png diff --git a/docs/RandomX_two.png b/docs/img/RandomX_two.png similarity index 100% rename from docs/RandomX_two.png rename to docs/img/RandomX_two.png diff --git a/pom.xml b/pom.xml index 1cc77421..2af11852 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,18 @@ jitpack.io https://jitpack.io + + consensys-maven + https://artifacts.consensys.net/public/maven/maven/ + + true + always + + + true + always + + @@ -86,7 +98,6 @@ true io.xdag.Bootstrap - ${git.commit.id.abbrev} ${maven.compiler.source} ${maven.compiler.target} @@ -137,8 +148,13 @@ *:* + junit:junit + netdb-testnet.txt + netdb-white-testnet.txt + *.config module-info.class META-INF/versions/9/*.class + META-INF/DISCLAIMER META-INF/NOTICE META-INF/NOTICE.txt META-INF/NOTICE.md @@ -169,11 +185,11 @@ LICENSE + en-mnemonic-word-list.txt io.xdag.Bootstrap - ${git.commit.id.abbrev} ${maven.compiler.source} ${maven.compiler.target} true @@ -185,35 +201,60 @@ + - pl.project13.maven - git-commit-id-plugin - 4.0.0 - - - get-the-git-infos - - revision - - - - validate-the-git-infos - - validateRevision - - package - - - - 40 - ${project.basedir}/.git - false - yyyy-MM-dd HH:mm:ss - git - true - ${project.build.outputDirectory}/git.properties - - + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + package + generate-resources + + run + + + + dist + ${dist.phase} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + run + + + + @@ -380,14 +421,6 @@ org.jetbrains.kotlinx kotlinx-coroutines-core - - - - - - org.jetbrains.kotlin - kotlin-stdlib-common - commons-codec commons-codec @@ -433,7 +466,7 @@ com.squareup.okhttp3 okhttp - 4.9.1 + 4.8.1 org.jetbrains @@ -441,13 +474,6 @@ - - - - - - - org.mockito @@ -490,8 +516,8 @@ org.apache.tuweni - tuweni-bytes - 1.1.0 + bytes + 1.3.0 com.google.guava @@ -500,6 +526,12 @@ + + org.apache.tuweni + units + 1.3.0 + + org.bouncycastle bcprov-jdk15on @@ -515,7 +547,7 @@ io.vertx vertx-core - 4.0.0 + 3.8.0 io.netty @@ -573,6 +605,10 @@ com.fasterxml.jackson.core jackson-core + + jackson-databind + com.fasterxml.jackson.core + @@ -594,6 +630,62 @@ 2.12.2 + + tech.pegasys.discovery + discovery + 0.4.6 + + + log4j-api + org.apache.logging.log4j + + + log4j-core + org.apache.logging.log4j + + + netty-all + io.netty + + + guava + com.google.guava + + + bcprov-jdk15on + org.bouncycastle + + + jackson-databind + com.fasterxml.jackson.core + + + logging-interceptor + com.squareup.okhttp3 + + + okhttp + com.squareup.okhttp3 + + + jackson-core + com.fasterxml.jackson.core + + + jffi + com.github.jnr + + + jnr-constants + com.github.jnr + + + jnr-ffi + com.github.jnr + + + + com.github.briandilley.jsonrpc4j @@ -621,8 +713,6 @@ 1.4.1 - - diff --git a/script/xdag.bat b/script/xdag.bat new file mode 100644 index 00000000..fbdbae59 --- /dev/null +++ b/script/xdag.bat @@ -0,0 +1,12 @@ +@echo off + +set XDAG_VERSION="0.4.2" +set XDAG_JARNAME="xdagj-%XDAG_VERSION%-shaded.jar" +set XDAG_OPTS="-t" + +#set JAVA_HOME="C:\Program Files\Java\jdk" + +# default JVM options +set JAVA_OPTS="--enable-preview -server -Xms1g -Xmx1g" + +java %JAVA_OPTS% -cp .;%XDAG_JARNAME% io.xdag.Bootstrap %* \ No newline at end of file diff --git a/script/xdag.sh b/script/xdag.sh index 0a935ac0..c6f77f3f 100755 --- a/script/xdag.sh +++ b/script/xdag.sh @@ -14,4 +14,4 @@ JAVA_HOME="/usr/local/java/" JAVA_OPTS="--enable-preview -server -Xms1g -Xmx1g" # start kernel -java ${JAVA_OPTS} -cp ${XDAG_JARNAME} io.xdag.Bootstrap "$@" \ No newline at end of file +java ${JAVA_OPTS} -cp .:${XDAG_JARNAME} io.xdag.Bootstrap "$@" \ No newline at end of file diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index aa2f2312..13b74715 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -39,10 +39,7 @@ import io.xdag.db.rocksdb.RocksdbFactory; import io.xdag.db.store.BlockStore; import io.xdag.db.store.OrphanPool; -import io.xdag.discovery.DiscoveryController; import io.xdag.event.EventProcesser; -import io.xdag.libp2p.Libp2pNetwork; -import io.xdag.libp2p.manager.ChannelManager; import io.xdag.mine.MinerServer; import io.xdag.mine.handler.ConnectionLimitHandler; import io.xdag.mine.manager.AwardManager; @@ -53,6 +50,8 @@ import io.xdag.mine.miner.MinerStates; import io.xdag.net.XdagClient; import io.xdag.net.XdagServer; +import io.xdag.net.discovery.DiscoveryController; +import io.xdag.net.libp2p.Libp2pNetwork; import io.xdag.net.manager.NetDBManager; import io.xdag.net.manager.XdagChannelManager; import io.xdag.net.message.MessageQueue; @@ -114,7 +113,6 @@ public class Kernel { protected XdagState xdagState; protected Libp2pNetwork libp2pNetwork; protected DiscoveryController discoveryController; - protected ChannelManager channelManager; protected AtomicInteger channelsAccount = new AtomicInteger(0); protected PrivKey privKey = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).component1(); @@ -235,7 +233,6 @@ public synchronized void testStart() throws Exception { // set up client // ==================================== - channelManager = new ChannelManager(); p2p = new XdagServer(this); p2p.start(); @@ -426,7 +423,6 @@ public synchronized void testStop() { nodeMgr.stop(); log.info("Node manager stop."); - channelManager.stop(); log.info("ChannelManager stop."); discoveryController.stop(); libp2pNetwork.stop(); @@ -459,9 +455,6 @@ public synchronized void testStop() { log.info("Release randomx"); } - public ChannelManager getLibp2pChannelManager() { - return channelManager; - } public void onSyncDone() { diff --git a/src/main/java/io/xdag/Launcher.java b/src/main/java/io/xdag/Launcher.java index a8b09375..9b604aad 100644 --- a/src/main/java/io/xdag/Launcher.java +++ b/src/main/java/io/xdag/Launcher.java @@ -89,9 +89,6 @@ protected void addOption(Option option) { * Parses options from the given arguments. */ protected CommandLine parseOptions(String[] args) throws ParseException { - if (args == null || args.length == 0 ) { - return null; - } CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse(getOptions(), args); diff --git a/src/main/java/io/xdag/cli/Commands.java b/src/main/java/io/xdag/cli/Commands.java index efa042c7..fe3c8955 100644 --- a/src/main/java/io/xdag/cli/Commands.java +++ b/src/main/java/io/xdag/cli/Commands.java @@ -506,7 +506,6 @@ public void stop() { public String listConnect() { Map map = kernel.getNodeMgr().getActiveNode(); - Map map0 = kernel.getNodeMgr().getActiveNode0(); StringBuilder stringBuilder = new StringBuilder(); for (Node node : map.keySet()) { stringBuilder @@ -519,19 +518,7 @@ public String listConnect() { .append(node.getStat().Outbound.get()) .append(" out").append(System.getProperty("line.separator")); } - for (Node node0 : map0.keySet()) { - stringBuilder - .append(node0.getAddress()) - .append(" ") - .append("libp2p") - .append(" ") - .append(map0.get(node0) == null ? null : FormatDateUtils.format(new Date(map0.get(node0)))) - .append(" ") - .append(node0.getStat().Inbound.get()) - .append(" in/") - .append(node0.getStat().Outbound.get()) - .append(" out").append(System.getProperty("line.separator")); - } + return stringBuilder.toString(); } diff --git a/src/main/java/io/xdag/cli/Shell.java b/src/main/java/io/xdag/cli/Shell.java index fde9cb66..821e2515 100644 --- a/src/main/java/io/xdag/cli/Shell.java +++ b/src/main/java/io/xdag/cli/Shell.java @@ -314,7 +314,7 @@ private void processXfer(CommandInput input) { } // xfer must check dnet password - if(!readPassword(false)) { + if(!readPassword("Enter Dnet password> ",false)) { return; } println(commands.xfer(amount, hash, remark)); @@ -455,6 +455,10 @@ private void processTerminate(CommandInput input) { if (opt.isSet("help")) { throw new Options.HelpException(opt.usage()); } + // before terminate must verify admin password(config at AdminSpec) + if(!readPassword("Enter Admin password> ",true)) { + return; + } commands.stop(); println("Stop."); } catch (Exception e) { @@ -462,11 +466,11 @@ private void processTerminate(CommandInput input) { } } - private boolean readPassword(boolean isTelnet) { + private boolean readPassword(String prompt, boolean isTelnet) { Character mask = '*'; String line; do { - line = reader.readLine("Enter password> ", mask); + line = reader.readLine(prompt, mask); } while (org.apache.commons.lang3.StringUtils.isEmpty(line)); if(isTelnet) { @@ -504,7 +508,7 @@ public void shell(Terminal terminal, Map environment) { this.setReader(reader); - if(!readPassword(true)) { + if(!readPassword("Enter Admin password>",true)) { return; } diff --git a/src/main/java/io/xdag/cli/XdagCli.java b/src/main/java/io/xdag/cli/XdagCli.java index 652516c3..c107ee25 100644 --- a/src/main/java/io/xdag/cli/XdagCli.java +++ b/src/main/java/io/xdag/cli/XdagCli.java @@ -48,6 +48,8 @@ import java.util.Objects; import java.util.Scanner; +import static io.xdag.wallet.WalletUtils.WALLET_PASSWORD_PROMPT; + public class XdagCli extends Launcher { private static final Scanner scanner = new Scanner(new InputStreamReader(System.in, StandardCharsets.UTF_8)); @@ -140,9 +142,7 @@ public void start(String[] args) throws Exception { System.err.println("Parsing Failed:" + exception.getMessage()); } - if(cmd == null) { - start(); - } else if (cmd.hasOption(XdagOption.HELP.toString())) { + if (cmd.hasOption(XdagOption.HELP.toString())) { printHelp(); } else if (cmd.hasOption(XdagOption.VERSION.toString())) { printVersion(); @@ -165,6 +165,8 @@ public void start(String[] args) throws Exception { } else if (cmd.hasOption(XdagOption.CONVERT_OLD_WALLET.toString())) { File file = new File(cmd.getOptionValue(XdagOption.CONVERT_OLD_WALLET.toString()).trim()); convertOldWallet(file); + } else { + start(); } } @@ -329,13 +331,15 @@ protected boolean importMnemonic(String mnemonic) { return false; } - // default add one hd key - createAccount(); - + wallet.initializeHdWallet(mnemonic); if (!wallet.flush()) { System.out.println("HDWallet File Cannot Be Updated"); return false; } + + // default add one hd key + createAccount(); + System.out.println("HDWallet Mnemonic Imported Successfully!"); return true; } @@ -345,7 +349,9 @@ protected boolean convertOldWallet(File file) { System.out.println("File:" + file.getName() + " not exists."); return false; } - List keyList = readOldWallet(file); + String password = readPassword("Old wallet password:"); + String random = readPassword("Old wallet random:"); + List keyList = readOldWallet(password, random, file); for(ECKeyPair key : keyList) { System.out.println("PrivateKey:" + BytesUtils.toHexString(key.getPrivateKey().toByteArray())); System.out.println(" PublicKey:" + BytesUtils.toHexString(key.getPublicKey().toByteArray())); @@ -355,13 +361,15 @@ protected boolean convertOldWallet(File file) { return true; } - private List readOldWallet(File walletDatFile) { + public List readOldWallet(String password, String random, File walletDatFile) { byte[] priv32Encrypted = new byte[32]; int keysNum = 0; List keyList = new ArrayList<>(); + Native.general_dnet_key(password, random); try (FileInputStream fileInputStream = new FileInputStream(walletDatFile)) { while (fileInputStream.read(priv32Encrypted) != -1) { byte[] priv32 = Native.uncrypt_wallet_key(priv32Encrypted, keysNum++); + BytesUtils.arrayReverse(priv32); ECKeyPair ecKey = ECKeyPair.create(Numeric.toBigInt(priv32)); keyList.add(ecKey); } @@ -383,7 +391,7 @@ public Wallet loadAndUnlockWallet() { if (wallet.unlock("")) { setPassword(""); } else { - setPassword(readPassword()); + setPassword(readPassword(WALLET_PASSWORD_PROMPT)); } } @@ -398,6 +406,7 @@ public Wallet loadAndUnlockWallet() { * Create a new wallet with a new password */ public Wallet createNewWallet() { + System.out.println("Create New Wallet..."); String newPassword = readNewPassword("EnterNewPassword:", "ReEnterNewPassword:"); if (newPassword == null) { return null; @@ -480,7 +489,4 @@ public String readPassword(String prompt) { return new String(console.readPassword(prompt)); } - public String readPassword() { - return readPassword("Please enter your password: "); - } -} +} \ No newline at end of file diff --git a/src/main/java/io/xdag/cli/XdagOption.java b/src/main/java/io/xdag/cli/XdagOption.java index fd6743e1..1fb8d0d2 100644 --- a/src/main/java/io/xdag/cli/XdagOption.java +++ b/src/main/java/io/xdag/cli/XdagOption.java @@ -41,8 +41,6 @@ public enum XdagOption { IMPORT_MNEMONIC("importmnemonic"), - ENABLE_RPC("enablerpc"), - CONVERT_OLD_WALLET("convertoldwallet"); private final String name; diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index 710f65a1..bb4f4a1f 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -30,15 +30,10 @@ import io.xdag.core.XdagField; import io.xdag.crypto.DnetKeys; import io.xdag.crypto.jni.Native; -import io.xdag.discovery.peers.DiscoveryPeer; -import io.xdag.discovery.peers.Endpoint; import io.xdag.rpc.modules.ModuleDescription; -import io.xdag.utils.discoveryutils.bytes.BytesValue; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Hex; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -46,7 +41,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.OptionalInt; @Slf4j @Getter @@ -119,7 +113,7 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa protected boolean isBootnode; protected int discoveryPort; protected String libp2pPrivkey; - protected List bootnodes = new ArrayList<>(); + protected List bootnodes = new ArrayList<>(); // ========================= // Wallet spec @@ -150,18 +144,6 @@ public void setDir() { netDBDir = getRootDir() + "/netdb.txt"; } - //todo:修改成一个配置文件读取种子节点 - protected List getBootnode() throws DecoderException { - //逻辑是先连接config里面节点再进行发现 - String id = "08021221027611680ca65e8fb7214a31b6ce6fcd8e6fe6a5f4d784dc6601dfe2bb9f8c96c2"; - byte [] peerid= Hex.decodeHex(id); - OptionalInt tcpport = OptionalInt.of(getDiscoveryPort()); - Endpoint endpoint = new Endpoint(getPoolIp(),getLibp2pPort(),tcpport); - BytesValue bytesValue= BytesValue.wrap(peerid); - DiscoveryPeer peer = new DiscoveryPeer(bytesValue,endpoint); - bootnodes.add(peer); - return bootnodes; - } protected AbstractConfig(String rootDir, String configName) { this.rootDir = rootDir; @@ -250,7 +232,10 @@ public void getSetting() { log.debug("{} IP access", list.length); whiteIPList.addAll(Arrays.asList(list)); } - + String[] bootnodelist = setting.getStrings("bootnode"); + if (bootnodelist != null) { + bootnodes.addAll(Arrays.asList(bootnodelist)); + } rpcEnabled = setting.getBool("isRPCEnabled") != null && setting.getBool("isRPCEnabled"); } diff --git a/src/main/java/io/xdag/config/RandomXConstants.java b/src/main/java/io/xdag/config/RandomXConstants.java index 3137045a..be3e84c5 100644 --- a/src/main/java/io/xdag/config/RandomXConstants.java +++ b/src/main/java/io/xdag/config/RandomXConstants.java @@ -32,7 +32,7 @@ public class RandomXConstants { public static long SEEDHASH_EPOCH_TESTNET_LAG = 64; public static final long RANDOMX_FORK_HEIGHT = 1540096; - public static long RANDOMX_TESTNET_FORK_HEIGHT = 40960000000L;// 196288 + public static long RANDOMX_TESTNET_FORK_HEIGHT = 409600000;// 196288 public static final int XDAG_RANDOMX = 2; diff --git a/src/main/java/io/xdag/config/TestnetConfig.java b/src/main/java/io/xdag/config/TestnetConfig.java index 1c1ca4d4..f37bcc83 100644 --- a/src/main/java/io/xdag/config/TestnetConfig.java +++ b/src/main/java/io/xdag/config/TestnetConfig.java @@ -33,7 +33,7 @@ public TestnetConfig() { this.whitelistUrl = "https://raw.githubusercontent.com/XDagger/xdag/master/client/netdb-white-testnet.txt"; // testnet wait 1 epoch - this.waitEpoch = 1; + this.waitEpoch = 10; this.xdagEra = 0x16900000000L; this.mainStartAmount = UnsignedLong.fromLongBits(1L << 42).longValue(); diff --git a/src/main/java/io/xdag/config/spec/NodeSpec.java b/src/main/java/io/xdag/config/spec/NodeSpec.java index 6c6382b7..510ac8b2 100644 --- a/src/main/java/io/xdag/config/spec/NodeSpec.java +++ b/src/main/java/io/xdag/config/spec/NodeSpec.java @@ -24,7 +24,6 @@ package io.xdag.config.spec; import io.xdag.crypto.DnetKeys; -import io.xdag.discovery.peers.DiscoveryPeer; import java.util.List; @@ -46,7 +45,7 @@ public interface NodeSpec { // libp2p boolean isBootnode() ; - List getBootnodes(); + List getBootnodes(); int getDiscoveryPort(); int getLibp2pPort(); String getLibp2pPrivkey(); diff --git a/src/main/java/io/xdag/consensus/SyncManager.java b/src/main/java/io/xdag/consensus/SyncManager.java index 4f7cf122..ce87fb83 100644 --- a/src/main/java/io/xdag/consensus/SyncManager.java +++ b/src/main/java/io/xdag/consensus/SyncManager.java @@ -24,19 +24,14 @@ package io.xdag.consensus; import com.google.common.collect.Queues; -import io.libp2p.core.PeerId; import io.xdag.Kernel; import io.xdag.config.Config; import io.xdag.config.MainnetConfig; import io.xdag.core.*; -import io.xdag.discovery.peers.DiscoveryPeer; -import io.xdag.discovery.peers.PeerTable; -import io.xdag.libp2p.Libp2pChannel; -import io.xdag.libp2p.manager.ChannelManager; -import io.xdag.libp2p.peer.LibP2PNodeId; +import io.xdag.net.Channel; +import io.xdag.net.discovery.DiscoveryPeer; import io.xdag.net.XdagChannel; import io.xdag.net.manager.XdagChannelManager; -import io.xdag.net.node.Node; import io.xdag.utils.ByteArrayWrapper; import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; @@ -53,7 +48,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.Stream; import static io.xdag.core.ImportResult.*; import static io.xdag.utils.FastByteComparisons.equalBytes; @@ -78,7 +72,6 @@ public Thread newThread(@Nonnull Runnable r) { private AtomicLong importIdleTime = new AtomicLong(); private boolean syncDone = false; private XdagChannelManager channelMgr; - private ChannelManager channelManager; private final ScheduledExecutorService exec; private ScheduledFuture connectlibp2pFuture; private Set hadConnectnode = new HashSet<>(); @@ -91,7 +84,6 @@ public SyncManager(Kernel kernel) { this.kernel = kernel; this.blockchain = kernel.getBlockchain(); this.channelMgr = kernel.getChannelMgr(); - this.channelManager = kernel.getChannelManager(); this.stateListener = new StateListener(); this.exec = new ScheduledThreadPoolExecutor(1, factory); @@ -158,7 +150,7 @@ public ImportResult importBlock(BlockWrapper blockWrapper) { ImportResult importResult = blockchain.tryToConnect(new Block(new XdagBlock(blockWrapper.getBlock().getXdagBlock().getData()))); if (importResult == EXIST) { - log.error("Block have exist:" + Hex.toHexString(blockWrapper.getBlock().getHash())); + log.debug("Block have exist:" + Hex.toHexString(blockWrapper.getBlock().getHash())); } Config config = kernel.getConfig(); @@ -211,19 +203,15 @@ public synchronized ImportResult validateAndAddNewBlock(BlockWrapper blockWrappe case NO_PARENT: { if (syncPushBlock(blockWrapper, result.getHashlow())) { log.debug("push block:{}, NO_PARENT {}", Hex.toHexString(blockWrapper.getBlock().getHashLow()), - Hex.toHexString(result.getHashlow())); - List channels = channelMgr.getActiveChannels(); - for (XdagChannel channel : channels) { + Hex.toHexString(result.getHashlow())); + List channels = channelMgr.getActiveChannels(); + for (Channel channel : channels) { if(channel.getNode().equals(blockWrapper.getRemoteNode())) { channel.getXdag().sendGetBlock(result.getHashlow()); } } -// for(Libp2pChannel libp2pChannel : channelManager.getactiveChannel()){ -// if(libp2pChannel.getNode().equals(blockWrapper.getRemoteNode())){ -// libp2pChannel.getHandler().getController().sendGetBlock(result.getHashLow()); -// } -// } + } break; } @@ -302,8 +290,8 @@ public void syncPopBlock(BlockWrapper blockWrapper) { if (syncPushBlock(bw, importResult.getHashlow())) { log.debug("push block:{}, NO_PARENT {}", Hex.toHexString(bw.getBlock().getHashLow()), Hex.toHexString(importResult.getHashlow())); - List channels = channelMgr.getActiveChannels(); - for (XdagChannel channel : channels) { + List channels = channelMgr.getActiveChannels(); + for (Channel channel : channels) { if (channel.getNode().equals(bw.getRemoteNode())) { channel.getXdag().sendGetBlock(importResult.getHashlow()); } @@ -383,33 +371,11 @@ public void makeSyncDone() { kernel.getMinerServer().start(); kernel.getPow().start(); // kernel.getBlockchain().registerListener(kernel.getPow()); - kernel.getLibp2pNetwork().start(); -// connectlibp2pFuture = exec.scheduleAtFixedRate(this::doConnectlibp2p,10,10, TimeUnit.SECONDS); +// kernel.getLibp2pNetwork().start(); } - public void doConnectlibp2p(){ - List libp2pChannels = kernel.getChannelManager().getactiveChannel(); - Stream nodes = libp2pChannels.stream().map(a->a.getNode()); - PeerTable peerTable = kernel.getDiscoveryController().getPeerTable(); - Collection discoveryPeers = peerTable.getAllPeers(); - List discoveryPeers1 = new ArrayList<>(discoveryPeers); - for (DiscoveryPeer d : discoveryPeers1) { - if ((d.getEndpoint().getHost().equals(kernel.getDiscoveryController().getMynode().getHost()) && - (d.getEndpoint().getTcpPort().equals(kernel.getDiscoveryController().getMynode().getTcpPort()))) - || hadConnectnode.contains(d) || - nodes.anyMatch(a -> a.equals(new Node(d.getEndpoint().getHost(), d.getEndpoint().getTcpPort().getAsInt())))) { - continue; - } - StringBuilder stringBuilder = new StringBuilder(); -// 连接格式 ("/ip4/192.168.3.5/tcp/11112/ipfs/16Uiu2HAmRfT8vNbCbvjQGsfqWUtmZvrj5y8XZXiyUz6HVSqZW8gy") - String id = new LibP2PNodeId(PeerId.fromHex(Hex.toHexString(d.getId().extractArray()))).toString(); - stringBuilder.append("/ip4/").append(d.getEndpoint().getHost()).append("/tcp/").append(d.getEndpoint().getTcpPort().getAsInt()). - append("/ipfs/").append(id); - kernel.getLibp2pNetwork().dail(stringBuilder.toString()); - hadConnectnode.add(d); - } - } + public void stop() { log.debug("sync manager stop"); if (this.stateListener.isRunning){ @@ -419,7 +385,6 @@ public void stop() { public void distributeBlock(BlockWrapper blockWrapper) { channelMgr.onNewForeignBlock(blockWrapper); - channelManager.onNewForeignBlock(blockWrapper); } } diff --git a/src/main/java/io/xdag/consensus/XdagPow.java b/src/main/java/io/xdag/consensus/XdagPow.java index 34f4b2e4..cd74608f 100644 --- a/src/main/java/io/xdag/consensus/XdagPow.java +++ b/src/main/java/io/xdag/consensus/XdagPow.java @@ -26,7 +26,6 @@ import io.xdag.Kernel; import io.xdag.core.*; import io.xdag.crypto.Hash; -import io.xdag.libp2p.manager.ChannelManager; import io.xdag.listener.Listener; import io.xdag.mine.MinerChannel; import io.xdag.mine.manager.AwardManager; @@ -88,8 +87,6 @@ public class XdagPow implements PoW, Listener, Runnable { private boolean isRunning = false; - private final ChannelManager channelManager; - protected RandomX randomXUtils; public XdagPow(Kernel kernel) { @@ -100,7 +97,6 @@ public XdagPow(Kernel kernel) { this.broadcaster = new Broadcaster(); this.minerManager = kernel.getMinerManager(); this.awardManager = kernel.getAwardManager(); - this.channelManager = kernel.getChannelManager(); this.randomXUtils = kernel.getRandomXUtils(); } @@ -134,7 +130,7 @@ public void stop() { } public void newBlock() { - log.info("Start new block generate...."); + log.debug("Start new block generate...."); long sendTime = XdagTime.getMainTime(); resetTimeout(sendTime); @@ -516,7 +512,6 @@ public void run() { } if(bw != null) { channelMgr.sendNewBlock(bw); - channelManager.sendNewBlock(bw); } } diff --git a/src/main/java/io/xdag/consensus/XdagSync.java b/src/main/java/io/xdag/consensus/XdagSync.java index 61a84d94..fa8279c5 100644 --- a/src/main/java/io/xdag/consensus/XdagSync.java +++ b/src/main/java/io/xdag/consensus/XdagSync.java @@ -26,6 +26,7 @@ import com.google.common.util.concurrent.SettableFuture; import io.xdag.Kernel; import io.xdag.db.store.BlockStore; +import io.xdag.net.Channel; import io.xdag.net.XdagChannel; import io.xdag.net.manager.XdagChannelManager; import io.xdag.utils.BytesUtils; @@ -101,13 +102,13 @@ private void requestBlocks(long t, long dt) { if (status != Status.SYNCING) { return; } - List any = getAnyNode(); + List any = getAnyNode(); long randomSeq; SettableFuture sf = SettableFuture.create(); if (any != null && any.size() != 0) { // TODO:随机选一个 int index = RandomUtils.nextInt()%any.size(); - XdagChannel xc = any.get(index); + Channel xc = any.get(index); if (dt <= REQUEST_BLOCKS_MAX_TIME) { randomSeq = xc.getXdag().sendGetBlocks(t, t + dt); // log.debug("sendGetBlocks seq:{}",randomSeq); @@ -155,7 +156,7 @@ private void requestBlocks(long t, long dt) { } } - public List getAnyNode() { + public List getAnyNode() { return channelMgr.getActiveChannels(); } diff --git a/src/main/java/io/xdag/core/BlockWrapper.java b/src/main/java/io/xdag/core/BlockWrapper.java index a684ff54..c806b728 100644 --- a/src/main/java/io/xdag/core/BlockWrapper.java +++ b/src/main/java/io/xdag/core/BlockWrapper.java @@ -23,7 +23,7 @@ */ package io.xdag.core; -import io.xdag.libp2p.peer.Libp2pNode; +import io.xdag.net.libp2p.peer.Libp2pNode; import io.xdag.net.node.Node; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/io/xdag/core/BlockchainImpl.java b/src/main/java/io/xdag/core/BlockchainImpl.java index b2c04856..7580f03a 100644 --- a/src/main/java/io/xdag/core/BlockchainImpl.java +++ b/src/main/java/io/xdag/core/BlockchainImpl.java @@ -23,8 +23,54 @@ */ package io.xdag.core; +import static io.xdag.config.Constants.BI_APPLIED; +import static io.xdag.config.Constants.BI_EXTRA; +import static io.xdag.config.Constants.BI_MAIN; +import static io.xdag.config.Constants.BI_MAIN_CHAIN; +import static io.xdag.config.Constants.BI_MAIN_REF; +import static io.xdag.config.Constants.BI_OURS; +import static io.xdag.config.Constants.BI_REF; +import static io.xdag.config.Constants.MAIN_BIG_PERIOD_LOG; +import static io.xdag.config.Constants.MAIN_CHAIN_PERIOD; +import static io.xdag.config.Constants.MAX_ALLOWED_EXTRA; +import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD; +import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD_TEST; +import static io.xdag.utils.BasicUtils.amount2xdag; +import static io.xdag.utils.BasicUtils.getDiffByHash; +import static io.xdag.utils.FastByteComparisons.equalBytes; +import static io.xdag.utils.MapUtils.getHead; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import org.apache.commons.collections4.CollectionUtils; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + import com.google.common.collect.Lists; import com.google.common.primitives.UnsignedLong; + import io.xdag.Kernel; import io.xdag.config.MainnetConfig; import io.xdag.crypto.ECDSASignature; @@ -39,33 +85,9 @@ import io.xdag.utils.ByteArrayWrapper; import io.xdag.utils.BytesUtils; import io.xdag.utils.XdagTime; -import io.xdag.wallet.KeyInternalItem; import io.xdag.wallet.Wallet; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; - -import javax.annotation.Nonnull; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import static io.xdag.config.Constants.*; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD; -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD_TEST; -import static io.xdag.utils.BasicUtils.amount2xdag; -import static io.xdag.utils.BasicUtils.getDiffByHash; -import static io.xdag.utils.FastByteComparisons.equalBytes; -import static io.xdag.utils.MapUtils.getHead; @Slf4j @Getter @@ -572,9 +594,9 @@ private UnsignedLong applyBlock(Block block) { // TODO: 改递归为迭代 private void applyBlock1(Block block) { List list=new ArrayList<>();//建立一个整数列表,一个节点列表,两个栈 - List curr=new ArrayList(); - Stack stack1=new Stack(); - Stack stack2=new Stack(); + List curr=new ArrayList<>(); + Stack stack1=new Stack<>(); + Stack stack2=new Stack<>(); if(block!=null){ //根不空,进栈1 stack1.push(block); while(!stack1.isEmpty()){//栈1不空出栈1,然后进栈2 diff --git a/src/main/java/io/xdag/discovery/DiscoveryController.java b/src/main/java/io/xdag/discovery/DiscoveryController.java deleted file mode 100644 index e8c762cc..00000000 --- a/src/main/java/io/xdag/discovery/DiscoveryController.java +++ /dev/null @@ -1,543 +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.discovery; - -import com.google.common.annotations.VisibleForTesting; -import io.libp2p.core.crypto.KEY_TYPE; -import io.libp2p.core.crypto.KeyKt; -import io.libp2p.core.crypto.PrivKey; -import io.vertx.core.Vertx; -import io.vertx.core.datagram.DatagramPacket; -import io.vertx.core.datagram.DatagramSocket; -import io.xdag.Kernel; -import io.xdag.discovery.data.Packet; -import io.xdag.discovery.data.PacketData; -import io.xdag.discovery.data.PacketType; -import io.xdag.discovery.message.FindNeighborsPacketData; -import io.xdag.discovery.message.NeighborsPacketData; -import io.xdag.discovery.message.PingPacketData; -import io.xdag.discovery.message.PongPacketData; -import io.xdag.discovery.peers.DiscoveryPeer; -import io.xdag.discovery.peers.Endpoint; -import io.xdag.discovery.peers.Peer; -import io.xdag.discovery.peers.PeerTable; -import io.xdag.utils.discoveryutils.PeerDiscoveryPacketDecodingException; -import io.xdag.utils.discoveryutils.PeerDiscoveryStatus; -import io.xdag.utils.discoveryutils.Subscribers; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.DecoderException; -import org.apache.tuweni.bytes.Bytes; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import static io.xdag.utils.discoveryutils.Preconditions.checkGuard; -import static io.xdag.utils.discoveryutils.bytes.MutableBytesValue.wrapBuffer; -import static java.util.Collections.emptyList; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.SECONDS; - -@Slf4j -public class DiscoveryController { - private boolean isbootnode; - private static final int MAX_PACKET_SIZE_BYTES = 1600; - private PeerTable peerTable; - private DatagramSocket socket; - private long lastRefreshTime = -1; - private DiscoveryPeer myself; - private Vertx vertx; - private Endpoint mynode; - private List bootnodes; - private PrivKey privKey; - private final Kernel kernel; - private static final long REFRESH_CHECK_INTERVAL_MILLIS = MILLISECONDS.convert(30, SECONDS); - private final long tableRefreshIntervalMs = MILLISECONDS.convert(30, SECONDS); - private final RetryDelayFunction retryDelayFunction = RetryDelayFunction.linear(1.5, 2000, 60000); - private final Map inflightInteractions = - new ConcurrentHashMap<>(); - private final Subscribers> peerBondedObservers = new Subscribers<>(); - - public DiscoveryController(Kernel kernel) { - this.kernel = kernel; - } - - public void start() throws DecoderException, IOException { - this.isbootnode = kernel.getConfig().getNodeSpec().isBootnode(); - final BytesValue myid ; - if(isbootnode){ - log.info("Seed node start"); - String prikey = this.kernel.getConfig().getNodeSpec().getLibp2pPrivkey(); - // id = 08021221027611680ca65e8fb7214a31b6ce6fcd8e6fe6a5f4d784dc6601dfe2bb9f8c96c2 - this.privKey = KeyKt.unmarshalPrivateKey(Bytes.fromHexString(prikey).toArrayUnsafe()); - myid = BytesValue.wrap(privKey.publicKey().bytes()); - }else { - //gen random nodeid - this.privKey = KeyKt.generateKeyPair(KEY_TYPE.SECP256K1).getFirst(); - myid = BytesValue.wrap(privKey.publicKey().bytes()); - } - mynode = new Endpoint(this.kernel.getConfig().getNodeSpec().getNodeIp(), - this.kernel.getConfig().getNodeSpec().getDiscoveryPort(),OptionalInt.of(this.kernel.getConfig().getNodeSpec().getLibp2pPort())); - myself = new DiscoveryPeer(myid,mynode); - peerTable = new PeerTable(myid, 16); - bootnodes = this.kernel.getConfig().getNodeSpec().getBootnodes(); - log.debug("bootnodes {}", bootnodes.toString()); - this.vertx = Vertx.vertx(); - vertx.createDatagramSocket().listen(mynode.getUdpPort(),mynode.getHost(), ar -> { - if (!ar.succeeded()) { - log.debug("seed node init fail"); - } else { - log.debug("seed node init success"); - } - socket = ar.result(); - socket.exceptionHandler(this::handleException); - socket.handler(this::handlePacket); - }); - - // 定时执行的线程 - timeRefreshTable(); - - if(!isbootnode){ - //先把种子节点加入peerTable里面,所以没有下面的添加成功 ADDED表示添加成功 - bootnodes.stream().filter(node -> { - try { - return peerTable.tryAdd(node).getOutcome() == PeerTable.AddResult.Outcome.ADDED; - } catch (IOException e) { - log.error(e.getMessage(), e); - } - return false; - }).forEach(node -> bond(node, true)); - } - } - - @VisibleForTesting - void bond(final DiscoveryPeer peer, final boolean bootstrap) { - peer.setFirstDiscovered(System.currentTimeMillis()); - peer.setStatus(PeerDiscoveryStatus.BONDING); - - final Consumer action = - interaction -> { - final PingPacketData data = - PingPacketData.create(myself.getEndpoint(), peer.getEndpoint()); - Packet sentPacket = null; - try { - sentPacket = sendPacket(peer, PacketType.PING, data); - } catch (IOException e) { - e.printStackTrace(); - } - final BytesValue pingHash = sentPacket.getHash(); - // Update the matching filter to only accept the PONG if it echoes the hash of our PING. - final Predicate newFilter = - packet -> - packet - .getPacketData(PongPacketData.class) - .map(pong -> pong.getPingHash().equals(pingHash)) - .orElse(false); - interaction.updateFilter(newFilter); - }; - - // The filter condition will be updated as soon as the action is performed. - final PeerInteractionState ping = - new PeerInteractionState(action, PacketType.PONG, (packet) -> false, true, bootstrap); - dispatchInteraction(peer, ping); - } - - public Packet sendPacket(final DiscoveryPeer peer, final PacketType type, final PacketData data) throws IOException { - - - final Packet packet = Packet.create(type , data, privKey); - socket.send( - packet.encode(), - peer.getEndpoint().getUdpPort(), - peer.getEndpoint().getHost(), - ar -> { - if (ar.failed()) { - log.warn( - "Sending to peer {} failed, packet: {}", - peer, - wrapBuffer(packet.encode()), - ar.cause()); - return; - } - if (ar.succeeded()) { - peer.setLastContacted(System.currentTimeMillis()); - } - }); - - return packet; - } - - private void dispatchInteraction(final Peer peer, final PeerInteractionState state) { - final PeerInteractionState previous = inflightInteractions.put(peer.getId(), state); - log.debug("inflightInteractions.put {} " ,peer.getId()); - if (previous != null) { - previous.cancelTimers(); - } - state.execute(0); - } - private void handleException(final Throwable exception) { - if (exception instanceof IOException) { - log.debug("Packet handler exception", exception); - } else { - log.error("Packet handler exception", exception); - } - } - // 30s询问一次时间是否够半小时 半小时刷新一次refreshTable - public void timeRefreshTable() { - log.debug("start RefreshTable"); - vertx.setPeriodic( - Math.min(REFRESH_CHECK_INTERVAL_MILLIS, tableRefreshIntervalMs), - (l) -> { - try { - refreshTableIfRequired(); - } catch (IOException e) { - e.printStackTrace(); - } - }); - } - - private void refreshTableIfRequired() throws IOException { - final long now = System.currentTimeMillis(); - if (lastRefreshTime + tableRefreshIntervalMs < now) { - log.debug("Peer table refresh triggered by timer expiry"); - refreshTable(); - } - } - - private void refreshTable() throws IOException { - final BytesValue target = Peer.randomId(); - peerTable.nearestPeers(Peer.randomId(), 16).forEach((peer) -> findNodes(peer, target)); - lastRefreshTime = System.currentTimeMillis(); - } - private void findNodes(final DiscoveryPeer peer, final BytesValue target) { - final Consumer action = - (interaction) -> { - final FindNeighborsPacketData data = FindNeighborsPacketData.create(target); - try { - sendPacket(peer, PacketType.FIND_NEIGHBORS, data); - } catch (IOException e) { - e.printStackTrace(); - } - }; - final PeerInteractionState interaction = - new PeerInteractionState(action, PacketType.NEIGHBORS, packet -> true, true, false); - dispatchInteraction(peer, interaction); - } - - private void handlePacket(final DatagramPacket datagram) { - try { - final int length = datagram.data().length(); - checkGuard( - length <= MAX_PACKET_SIZE_BYTES, - PeerDiscoveryPacketDecodingException::new, - "Packet too large. Actual size (bytes): %s", - length); - - // We allow exceptions to bubble up, as they'll be picked up by the exception handler. -// System.out.println("privKey.publicKey().bytes() = " + Hex.toHexString(privKey.publicKey().bytes())); - final Packet packet = Packet.decode(datagram.data()); - - OptionalInt fromPort = OptionalInt.empty(); - if (packet.getPacketData(PingPacketData.class).isPresent()) { - final PingPacketData ping = packet.getPacketData(PingPacketData.class).orElseGet(null); - if (ping != null && ping.getFrom() != null && ping.getFrom().getTcpPort().isPresent()) { - fromPort = ping.getFrom().getTcpPort(); - } - } - - // Acquire the senders coordinates to build a Peer representation from them. - final String addr = datagram.sender().host(); - final int port = datagram.sender().port(); - - // Notify the peer controller. - final DiscoveryPeer peer = new DiscoveryPeer(packet.getNodeId(), addr, port, fromPort); -// System.out.println("packet.getNodeId() = "+ packet.getNodeId()); - onMessage(packet, peer); - } catch (final PeerDiscoveryPacketDecodingException e) { - log.debug("Discarding invalid peer discovery packet", e); - } catch (final Throwable t) { - log.error("Encountered error while handling packet", t); - } - } - - public void onMessage(final Packet packet, final DiscoveryPeer sender) throws IOException { - log.debug("Received Packet Type {}",packet.getType()); - // Message from self. This should not happen. - if (sender.getId().equals(myself.getId())) { - log.debug("发送人是自己"); - return; - } - - // Load the peer from the table, or use the instance that comes in. - final Optional maybeKnownPeer = peerTable.get(sender); - final DiscoveryPeer peer = maybeKnownPeer.orElse(sender); - - switch (packet.getType()) { - case PING: - if (addToPeerTable(peer)) { - log.debug("Table成功添加peer"); - final PingPacketData ping = packet.getPacketData(PingPacketData.class).get(); - respondToPing(ping, packet.getHash(), peer); - } - - break; - case PONG: - { - matchInteraction(packet) - .ifPresent( - interaction -> { - log.debug("Table成功添加peer"); - try { - addToPeerTable(peer); - } catch (IOException e) { - e.printStackTrace(); - } - - // If this was a bootstrap peer, let's ask it for nodes near to us. - // 如果是种子节点就询问对方离我最近的节点 - if (interaction.isBootstrap()) { - log.debug("interaction.isBootstrap() = {}" ,interaction.isBootstrap()); - findNodes(peer, myself.getId()); - } - }); - break; - } - case NEIGHBORS: - - matchInteraction(packet) - .ifPresent( - interaction -> { - // Extract the peers from the incoming packet. - log.debug("enter NEIGHBORS"); - final List neighbors = - packet - .getPacketData(NeighborsPacketData.class) - .map(NeighborsPacketData::getNodes) - .orElse(emptyList()); - //向peerTable没有的peer发送ping消息 - for (final DiscoveryPeer neighbor : neighbors) { - System.out.println("neighbors.size() = " + neighbors.size()); - try { - if (peerTable.get(neighbor).isPresent() || myself.getId().equals(neighbor.getId())) { - log.debug("peerTable had this peer or not ping myself"); - continue; - } - } catch (IOException e) { - e.printStackTrace(); - } - //todo - log.debug("bond new peer and neighbor.getId() ="+ neighbor.getId()); - bond(neighbor, false); - } - }); - break; - - case FIND_NEIGHBORS: - final FindNeighborsPacketData fn = - packet.getPacketData(FindNeighborsPacketData.class).get(); - respondToFindNeighbors(fn, peer); - break; - } - } - - private void respondToPing( - final PingPacketData packetData, final BytesValue pingHash, final DiscoveryPeer sender) throws IOException { - final PongPacketData data = PongPacketData.create(packetData.getFrom(), pingHash); - sendPacket(sender, PacketType.PONG, data); - } - private void respondToFindNeighbors( - final FindNeighborsPacketData packetData, final DiscoveryPeer sender) throws IOException { - // TODO: for now return 16 peers. Other implementations calculate how many - // peers they can fit in a 1280-byte payload. - final List peers = peerTable.nearestPeers(packetData.getTarget(), 16); - log.debug("DiscoveryPeer number {}",peers.size()); - final PacketData data = NeighborsPacketData.create(peers); - sendPacket(sender, PacketType.NEIGHBORS, data); - } - - private boolean addToPeerTable(final DiscoveryPeer peer) throws IOException { - final PeerTable.AddResult result = peerTable.tryAdd(peer); - if (result.getOutcome() == PeerTable.AddResult.Outcome.SELF) { - return false; - } - - // Reset the last seen timestamp. - final long now = System.currentTimeMillis(); - if (peer.getFirstDiscovered() == 0) { - peer.setFirstDiscovered(now); - } - peer.setLastSeen(now); - - if (peer.getStatus() != PeerDiscoveryStatus.BONDED) { - peer.setStatus(PeerDiscoveryStatus.BONDED); - notifyPeerBonded(peer, now); - } - - if (result.getOutcome() == PeerTable.AddResult.Outcome.ALREADY_EXISTED) { - // Bump peer. - peerTable.evict(peer); - peerTable.tryAdd(peer); - } else if (result.getOutcome() == PeerTable.AddResult.Outcome.BUCKET_FULL) { - peerTable.evict(result.getEvictionCandidate()); - peerTable.tryAdd(peer); - } - - return true; - } - - private void notifyPeerBonded(final DiscoveryPeer peer, final long now) { - final PeerDiscoveryEvent.PeerBondedEvent event = new PeerDiscoveryEvent.PeerBondedEvent(peer, now); - dispatchEvent(peerBondedObservers, event); - } - public Endpoint getMynode(){ - return mynode; - } - - public PeerTable getPeerTable(){ - return peerTable; - } - - public CompletableFuture stop() { - if (socket == null) { - return CompletableFuture.completedFuture(null); - } - - final CompletableFuture completion = new CompletableFuture<>(); - socket.close( - ar -> { - if (ar.succeeded()) { - inflightInteractions.values().forEach(PeerInteractionState::cancelTimers); - inflightInteractions.clear(); - socket = null; - completion.complete(null); - } else { - completion.completeExceptionally(ar.cause()); - } - }); - return completion; - } - - private class PeerInteractionState implements Predicate { - /** - * The action that led to the peer being in this state (e.g. sending a PING or NEIGHBORS - * message), in case it needs to be retried. - */ - private final Consumer action; - /** - * The expected type of the message that will transition the peer out of this state. - */ - private final PacketType expectedType; - /** - * A custom filter to accept transitions out of this state. - */ - private Predicate filter; - /** - * Whether the action associated to this state is retryable or not. - */ - private final boolean retryable; - /** - * Whether this is an entry for a bootstrap peer. - */ - private final boolean bootstrap; - /** - * Timers associated with this entry. - */ - private OptionalLong timerId = OptionalLong.empty(); - - PeerInteractionState( - final Consumer action, - final PacketType expectedType, - final Predicate filter, - final boolean retryable, - final boolean bootstrap) { - this.action = action; - this.expectedType = expectedType; - this.filter = filter; - this.retryable = retryable; - this.bootstrap = bootstrap; - } - - @Override - public boolean test(final Packet packet) { - return expectedType == packet.getType() && (filter == null || filter.test(packet)); - } - - void updateFilter(final Predicate filter) { - this.filter = filter; - } - - boolean isBootstrap() { - return bootstrap; - } - - /** - * Executes the action associated with this state. Sets a "boomerang" timer to itself in case - * the action is retryable. - * - * @param lastTimeout the previous timeout, or 0 if this is the first time the action is being - * executed. - */ - void execute(final long lastTimeout) { - action.accept(this); - if (retryable) { - final long newTimeout = retryDelayFunction.apply(lastTimeout); - timerId = OptionalLong.of(vertx.setTimer(newTimeout, id -> execute(newTimeout))); - } - } - - - void cancelTimers() { - timerId.ifPresent(vertx::cancelTimer); - } - } - private void dispatchEvent( - final Subscribers> observers, final T event) { - observers.forEach( - observer -> - vertx.executeBlocking( - future -> { - observer.accept(event); - future.complete(); - }, - x -> {})); - } - private Optional matchInteraction(final Packet packet) { - final PeerInteractionState interaction = inflightInteractions.get(packet.getNodeId()); - log.debug("packet.getNodeId() = {}",packet.getNodeId()); - if (interaction == null || !interaction.test(packet)) { - log.debug("interaction == null = {}",interaction == null); - log.debug("return Optional.empty()"); - return Optional.empty(); - } - System.out.println("互动匹配"); - interaction.cancelTimers(); - inflightInteractions.remove(packet.getNodeId()); - return Optional.of(interaction); - } -} - diff --git a/src/main/java/io/xdag/discovery/PeerDiscoveryEvent.java b/src/main/java/io/xdag/discovery/PeerDiscoveryEvent.java deleted file mode 100644 index 8ab7f5cd..00000000 --- a/src/main/java/io/xdag/discovery/PeerDiscoveryEvent.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.discovery; - -import com.google.common.base.MoreObjects; -import io.xdag.discovery.peers.DiscoveryPeer; - -public abstract class PeerDiscoveryEvent { - private final DiscoveryPeer peer; - private final long timestamp; - - private PeerDiscoveryEvent(final DiscoveryPeer peer, final long timestamp) { - this.peer = peer; - this.timestamp = timestamp; - } - - public DiscoveryPeer getPeer() { - return peer; - } - - public long getTimestamp() { - return timestamp; - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("peer", peer) - .add("timestamp", timestamp) - .toString(); - } - - - public static class PeerBondedEvent extends PeerDiscoveryEvent { - public PeerBondedEvent(final DiscoveryPeer peer, final long timestamp) { - super(peer, timestamp); - } - } - -} diff --git a/src/main/java/io/xdag/discovery/RetryDelayFunction.java b/src/main/java/io/xdag/discovery/RetryDelayFunction.java deleted file mode 100644 index bdaf3dd2..00000000 --- a/src/main/java/io/xdag/discovery/RetryDelayFunction.java +++ /dev/null @@ -1,33 +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.discovery; - -import java.util.function.UnaryOperator; - -interface RetryDelayFunction extends UnaryOperator { - - static RetryDelayFunction linear(final double multiplier, final long min, final long max) { - return (prev) -> Math.min(Math.max((long) Math.ceil(prev * multiplier), min), max); - } -} diff --git a/src/main/java/io/xdag/discovery/data/Packet.java b/src/main/java/io/xdag/discovery/data/Packet.java deleted file mode 100644 index a62cc3d4..00000000 --- a/src/main/java/io/xdag/discovery/data/Packet.java +++ /dev/null @@ -1,179 +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.discovery.data; - - -import io.libp2p.core.crypto.PrivKey; -import io.vertx.core.buffer.Buffer; -import io.xdag.utils.discoveryutils.PeerDiscoveryPacketDecodingException; -import lombok.extern.slf4j.Slf4j; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.BytesValueRLPOutput; -import io.xdag.utils.discoveryutils.bytes.MutableBytesValue; -import io.xdag.utils.discoveryutils.bytes.RLP; - -import java.io.IOException; -import java.util.Arrays; -import java.util.Optional; - -import static io.xdag.utils.discoveryutils.cryto.Hash.sha256; - -@Slf4j -public class Packet { - // index len - // 0 hash len = 32 - // 32 LenthIndex len = 1 - // 33 packtype len = 1 - // 34 pubkey len = 37 - // 71 Signatrue len = Len - // 71+Len data len = size - - private static final int LENGTH_INDEX = 32; - private static final int TYPE_INDEX = 33; - private static final int PUBKEY_INDEX = 71; - private static byte Signature_Len; - private final PacketType type; - private final PacketData data; - private final BytesValue hash; - private final BytesValue signature; - private final BytesValue publicKey; - - private Packet(final PacketType type, final PacketData data ,PrivKey pri) throws IOException { - this.type = type; - this.data = data; - final BytesValue typeBytes = BytesValue.of(this.type.getValue()); - final BytesValue dataBytes = RLP.encode(this.data::writeTo); - this.signature = BytesValue.wrap(pri.sign(BytesValue.wrap(typeBytes, dataBytes).extractArray())); - Signature_Len = (byte) (signature.size()); - this.publicKey = BytesValue.wrap(pri.publicKey().bytes()); - this.hash = sha256(BytesValue.wrap(BytesValue.wrap(BytesValue.wrap( - BytesValue.wrap(BytesValue.of(Signature_Len),typeBytes),publicKey),signature),dataBytes)); - } - - private Packet( - final PacketType packetType, final PacketData packetData, final BytesValue message) throws IOException { - this.type = packetType; - this.data = packetData; - this.hash = message.slice(0, 32); - Signature_Len = message.get(LENGTH_INDEX); - this.publicKey = message.slice(TYPE_INDEX + 1, 37); - this.signature= message.slice(PUBKEY_INDEX , Signature_Len); - final BytesValue rest = message.slice(LENGTH_INDEX, message.size() - LENGTH_INDEX); - if (!Arrays.equals(sha256(rest).extractArray(), hash.extractArray())) { - throw new PeerDiscoveryPacketDecodingException( - "Integrity check failed: non-matching hashes."); - } - } - - - public static Packet create( - final PacketType packetType, final PacketData packetData ,PrivKey privKey) throws IOException { - return new Packet(packetType, packetData, privKey); - } - - public static Packet decode(final Buffer message) throws IOException { - final byte type = message.getByte(TYPE_INDEX); - Signature_Len = message.getByte(LENGTH_INDEX); - final PacketType packetType = - PacketType.forByte(type) - .orElseThrow( - () -> - new PeerDiscoveryPacketDecodingException("Unrecognized packet type: " + type)); - - final PacketType.Deserializer deserializer = packetType.getDeserializer(); - final PacketData packetData; - try { - packetData = deserializer.deserialize(RLP.input(message, Signature_Len + 71)); - } catch (final Exception e) { - throw new PeerDiscoveryPacketDecodingException("Malformed packet of type: " + packetType, e); - } - - return new Packet(packetType, packetData, BytesValue.wrapBuffer(message)); - } - - public Buffer encode() { - final BytesValue signature = this.signature; - final BytesValueRLPOutput encodedData = new BytesValueRLPOutput(); - data.writeTo(encodedData); - final Buffer buffer = - Buffer.buffer(hash.size() + signature.size() + 2 + encodedData.encodedSize()); - hash.appendTo(buffer); - Signature_Len = (byte) (signature.size()); - buffer.appendByte(Signature_Len); - buffer.appendByte(type.getValue()); - buffer.appendBytes(publicKey.extractArray()); - signature.appendTo(buffer); - appendEncoded(encodedData, buffer); - return buffer; - } - - protected void appendEncoded(final BytesValueRLPOutput encoded, final Buffer buffer) { - final int size = encoded.encodedSize(); - if (size == 0) { - return; - } - // We want to append to the buffer, and Buffer always grows to accommodate anything writing, - // so we write the last byte we know we'll need to make it resize accordingly. - final int start = buffer.length(); - buffer.setByte(start + size - 1, (byte) 0); - encoded.writeEncoded(MutableBytesValue.wrapBuffer(buffer, start, size)); - } - - @SuppressWarnings("unchecked") - public Optional getPacketData(final Class expectedPacketType) { - if (data == null || !data.getClass().equals(expectedPacketType)) { - return Optional.empty(); - } - return Optional.of((T) data); - } - - public BytesValue getNodeId() { - return publicKey; - } - - public PacketType getType() { - return type; - } - - public BytesValue getHash() { - return hash; - } - - @Override - public String toString() { - return "Packet{" - + "type=" - + type - + ", data=" - + data - + ", hash=" - + hash - + ", signature=" - + signature - + ", publicKey=" - + publicKey - + '}'; - } - -} diff --git a/src/main/java/io/xdag/discovery/data/PacketData.java b/src/main/java/io/xdag/discovery/data/PacketData.java deleted file mode 100644 index 463288e0..00000000 --- a/src/main/java/io/xdag/discovery/data/PacketData.java +++ /dev/null @@ -1,42 +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.discovery.data; - -import io.xdag.utils.discoveryutils.bytes.RLPOutput; - -public interface PacketData { - /** - * Expiration is not standardised. We use Geth's expiration period (60 seconds); whereas Parity's - * is 20 seconds. - */ - long DEFAULT_EXPIRATION_PERIOD_MS = 60000; - - /** - * Serializes the implementing packet data onto the provided RLP output buffer. - * - * @param out The RLP output buffer. - */ - void writeTo(RLPOutput out); -} - diff --git a/src/main/java/io/xdag/discovery/data/PacketType.java b/src/main/java/io/xdag/discovery/data/PacketType.java deleted file mode 100644 index 4f546989..00000000 --- a/src/main/java/io/xdag/discovery/data/PacketType.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.discovery.data; - -import io.xdag.discovery.message.FindNeighborsPacketData; -import io.xdag.discovery.message.NeighborsPacketData; -import io.xdag.discovery.message.PingPacketData; -import io.xdag.discovery.message.PongPacketData; -import io.xdag.utils.discoveryutils.RLPInput; - -import javax.annotation.concurrent.Immutable; -import java.util.Arrays; -import java.util.Optional; - -import static com.google.common.base.Preconditions.checkArgument; - -public enum PacketType { - PING(0x01, PingPacketData::readFrom), - PONG(0x02, PongPacketData::readFrom), - FIND_NEIGHBORS(0x03, FindNeighborsPacketData::readFrom), - NEIGHBORS(0x04, NeighborsPacketData::readFrom); - - private static final int MAX_VALUE = 0x7F; - private static final int BYTE_MASK = 0xFF; - - private static final PacketType[] INDEX = new PacketType[PacketType.MAX_VALUE]; - - static { - Arrays.stream(values()).forEach(type -> INDEX[type.value] = type); - } - - private final byte value; - private final Deserializer deserializer; - - public static Optional forByte(final byte b) { - return b >= MAX_VALUE || b < 0 ? Optional.empty() : Optional.ofNullable(INDEX[b]); - } - - PacketType(final int value, final Deserializer deserializer) { - checkArgument(value <= MAX_VALUE, "Packet type ID must be in range [0x00, 0x80)"); - this.deserializer = deserializer; - this.value = (byte) (value & BYTE_MASK); - } - - public byte getValue() { - return value; - } - - public Deserializer getDeserializer() { - return deserializer; - } - - @FunctionalInterface - @Immutable - public interface Deserializer { - T deserialize(RLPInput in); - } -} diff --git a/src/main/java/io/xdag/discovery/message/FindNeighborsPacketData.java b/src/main/java/io/xdag/discovery/message/FindNeighborsPacketData.java deleted file mode 100644 index 620f07e9..00000000 --- a/src/main/java/io/xdag/discovery/message/FindNeighborsPacketData.java +++ /dev/null @@ -1,84 +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.discovery.message; - - -import io.xdag.discovery.data.PacketData; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; - -import static com.google.common.base.Preconditions.checkArgument; - -public class FindNeighborsPacketData implements PacketData { - private static final int TARGET_SIZE = 37; - - /* Node ID. */ - private final BytesValue target; - - /* In millis after epoch. */ - private final long expiration; - - private FindNeighborsPacketData(final BytesValue target, final long expiration) { - checkArgument(target != null && target.size() == TARGET_SIZE, "target must be a valid node id"); - checkArgument(expiration >= 0, "expiration must be positive"); - - this.target = target; - this.expiration = expiration; - } - - public static FindNeighborsPacketData create(final BytesValue target) { - return new FindNeighborsPacketData( - target, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); - } - - @Override - public void writeTo(final RLPOutput out) { - out.startList(); - out.writeBytesValue(target); - out.writeLongScalar(expiration); - out.endList(); - } - - public static FindNeighborsPacketData readFrom(final RLPInput in) { - in.enterList(); - final BytesValue target = in.readBytesValue(); - final long expiration = in.readLongScalar(); - in.leaveList(); - return new FindNeighborsPacketData(target, expiration); - } - - public long getExpiration() { - return expiration; - } - - public BytesValue getTarget() { - return target; - } - - @Override - public String toString() { - return "FindNeighborsPacketData{" + "expiration=" + expiration + ", target=" + target + '}'; - } -} diff --git a/src/main/java/io/xdag/discovery/message/NeighborsPacketData.java b/src/main/java/io/xdag/discovery/message/NeighborsPacketData.java deleted file mode 100644 index 944c2c6e..00000000 --- a/src/main/java/io/xdag/discovery/message/NeighborsPacketData.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.discovery.message; - -import io.xdag.discovery.data.PacketData; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; -import lombok.extern.slf4j.Slf4j; -import io.xdag.discovery.peers.DefaultPeer; -import io.xdag.discovery.peers.DiscoveryPeer; -import io.xdag.discovery.peers.Peer; - -import java.util.List; - -import static com.google.common.base.Preconditions.checkArgument; - -@Slf4j -public class NeighborsPacketData implements PacketData { - - private final List peers; - - /* In millis after epoch. */ - private final long expiration; - - private NeighborsPacketData(final List peers, final long expiration) { - checkArgument(peers != null, "peer list cannot be null"); - checkArgument(expiration >= 0, "expiration must be positive"); - - this.peers = peers; - this.expiration = expiration; - } - - public static NeighborsPacketData create(final List peers) { - log.info("create NeighborsPacketData success"); - return new NeighborsPacketData( - peers, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); - } - - public static NeighborsPacketData readFrom(final RLPInput in) { - in.enterList(); - final List peers = - in.readList(rlp -> new DiscoveryPeer(DefaultPeer.readFrom(rlp))); - log.info("peers nums = "+peers.size()); - final long expiration = in.readLongScalar(); - in.leaveList(); - return new NeighborsPacketData(peers, expiration); - } - - @Override - public void writeTo(final RLPOutput out) { - out.startList(); - out.writeList(peers, Peer::writeTo); - out.writeLongScalar(expiration); - out.endList(); - } - - public List getNodes() { - return peers; - } - - public long getExpiration() { - return expiration; - } - - @Override - public String toString() { - return String.format("NeighborsPacketData{peers=%s, expiration=%d}", peers, expiration); - } -} diff --git a/src/main/java/io/xdag/discovery/message/PingPacketData.java b/src/main/java/io/xdag/discovery/message/PingPacketData.java deleted file mode 100644 index 5f19f31e..00000000 --- a/src/main/java/io/xdag/discovery/message/PingPacketData.java +++ /dev/null @@ -1,109 +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.discovery.message; - -import io.xdag.discovery.data.PacketData; -import io.xdag.utils.discoveryutils.PeerDiscoveryPacketDecodingException; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; -import io.xdag.discovery.peers.Endpoint; - -import java.math.BigInteger; - -import static io.xdag.utils.discoveryutils.Preconditions.checkGuard; -import static com.google.common.base.Preconditions.checkArgument; - -public class PingPacketData implements PacketData { - - /* Fixed value that represents we're using v4 of the P2P discovery protocol. */ - private static final int VERSION = 4; - - /* Source. */ - private final Endpoint from; - - /* Destination. */ - private final Endpoint to; - - /* In millis after epoch. */ - private final long expiration; - - private PingPacketData(final Endpoint from, final Endpoint to, final long expiration) { - checkArgument(from != null, "source endpoint cannot be null"); - checkArgument(to != null, "destination endpoint cannot be null"); - checkArgument(expiration >= 0, "expiration cannot be negative"); - - this.from = from; - this.to = to; - this.expiration = expiration; - } - - public static PingPacketData create(final Endpoint from, final Endpoint to) { - return new PingPacketData( - from, to, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); - } - - public static PingPacketData readFrom(final RLPInput in) { - in.enterList(); - final BigInteger version = in.readBigIntegerScalar(); - checkGuard( - version.intValue() == VERSION, - PeerDiscoveryPacketDecodingException::new, - "Version mismatch in ping packet. Expected: %s, got: %s.", - VERSION, - version); - - final Endpoint from = Endpoint.decodeStandalone(in); - final Endpoint to = Endpoint.decodeStandalone(in); - final long expiration = in.readLongScalar(); - in.leaveList(); - return new PingPacketData(from, to, expiration); - } - - @Override - public void writeTo(final RLPOutput out) { - out.startList(); - out.writeIntScalar(VERSION); - from.encodeStandalone(out); - to.encodeStandalone(out); - out.writeLongScalar(expiration); - out.endList(); - } - - public Endpoint getFrom() { - return from; - } - - public Endpoint getTo() { - return to; - } - - public long getExpiration() { - return expiration; - } - - @Override - public String toString() { - return "PingPacketData{" + "from=" + from + ", to=" + to + ", expiration=" + expiration + '}'; - } -} diff --git a/src/main/java/io/xdag/discovery/message/PongPacketData.java b/src/main/java/io/xdag/discovery/message/PongPacketData.java deleted file mode 100644 index f4fd4d32..00000000 --- a/src/main/java/io/xdag/discovery/message/PongPacketData.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.discovery.message; - -import io.xdag.discovery.data.PacketData; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; -import io.xdag.discovery.peers.Endpoint; - -public class PongPacketData implements PacketData { - private final Endpoint to; - - /* Hash of the PING packet. */ - private final BytesValue pingHash; - - /* In millis after epoch. */ - private final long expiration; - - private PongPacketData(final Endpoint to, final BytesValue pingHash, final long expiration) { - this.to = to; - this.pingHash = pingHash; - this.expiration = expiration; - } - - public static PongPacketData create(final Endpoint to, final BytesValue pingHash) { - return new PongPacketData( - to, pingHash, System.currentTimeMillis() + PacketData.DEFAULT_EXPIRATION_PERIOD_MS); - } - - public static PongPacketData readFrom(final RLPInput in) { - in.enterList(); - final Endpoint to = Endpoint.decodeStandalone(in); - final BytesValue hash = in.readBytesValue(); - final long expiration = in.readLongScalar(); - in.leaveList(); - return new PongPacketData(to, hash, expiration); - } - - @Override - public void writeTo(final RLPOutput out) { - out.startList(); - to.encodeStandalone(out); - out.writeBytesValue(pingHash); - out.writeLongScalar(expiration); - out.endList(); - } - - @Override - public String toString() { - return "PongPacketData{" - + "to=" - + to - + ", pingHash=" - + pingHash - + ", expiration=" - + expiration - + '}'; - } - - public Endpoint getTo() { - return to; - } - - public BytesValue getPingHash() { - return pingHash; - } - - public long getExpiration() { - return expiration; - } - -} diff --git a/src/main/java/io/xdag/discovery/peers/Bucket.java b/src/main/java/io/xdag/discovery/peers/Bucket.java deleted file mode 100755 index ea8198ac..00000000 --- a/src/main/java/io/xdag/discovery/peers/Bucket.java +++ /dev/null @@ -1,109 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import lombok.extern.slf4j.Slf4j; - -import java.util.Arrays; -import java.util.List; -import java.util.Optional; - -import static java.lang.System.arraycopy; -import static java.util.Arrays.asList; -import static java.util.Arrays.copyOf; -import static java.util.Collections.unmodifiableList; - -@Slf4j -public class Bucket { - private final DiscoveryPeer[] kBucket; - private final int bucketSize; - private int tailIndex = -1; - - public Bucket(int bucketSize) { - this.bucketSize = bucketSize; - kBucket = new DiscoveryPeer[bucketSize]; - } - - synchronized Optional getAndTouch(final BytesValue id) { - for (int i = 0; i <= tailIndex; i++) { - final DiscoveryPeer p = kBucket[i]; - if (id.equals(p.getId())) { - arraycopy(kBucket, 0, kBucket, 1, i); - kBucket[0] = p; - return Optional.of(p); - } - } - return Optional.empty(); - } - - synchronized Optional add(final DiscoveryPeer peer) - throws IllegalArgumentException { - assert tailIndex >= -1 && tailIndex < bucketSize; - - // Avoid duplicating the peer if it already exists in the bucket. - for (int i = 0; i <= tailIndex; i++) { - if (peer.equals(kBucket[i])) { - throw new IllegalArgumentException( - String.format("Tried to add duplicate peer to k-bucket: %s", peer.getId())); - } - } - if (tailIndex == bucketSize - 1) { - return Optional.of(kBucket[tailIndex]); - } - arraycopy(kBucket, 0, kBucket, 1, ++tailIndex); - kBucket[0] = peer; - return Optional.empty(); - } - - synchronized boolean evict(final PeerId peer) { - // If the bucket is empty, there's nothing to evict. - if (tailIndex < 0) { - return false; - } - // If found, shift all subsequent elements to the left, and decrement tailIndex. - for (int i = 0; i <= tailIndex; i++) { - if (peer.equals(kBucket[i])) { - arraycopy(kBucket, i + 1, kBucket, i, tailIndex - i); - kBucket[tailIndex--] = null; - return true; - } - } - return false; - } - - synchronized List peers() { - return unmodifiableList(asList(copyOf(kBucket, tailIndex + 1))); - - } - - @Override - public String toString() { - return "peer.Bucket{" + - "kBucket=" + Arrays.toString(kBucket) + - ", bucketSize=" + bucketSize + - ", tailIndex=" + tailIndex + - '}'; - } -} diff --git a/src/main/java/io/xdag/discovery/peers/DefaultPeer.java b/src/main/java/io/xdag/discovery/peers/DefaultPeer.java deleted file mode 100644 index a525aa71..00000000 --- a/src/main/java/io/xdag/discovery/peers/DefaultPeer.java +++ /dev/null @@ -1,198 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.NetworkUtility; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import com.google.common.net.InetAddresses; -import com.google.common.primitives.Ints; - -import java.net.URI; -import java.util.Objects; -import java.util.Optional; -import java.util.OptionalInt; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -public class DefaultPeer extends DefaultPeerId implements Peer { - - public static final int PEER_ID_SIZE = 37; - - public static final int DEFAULT_PORT = 30303; - private static final Pattern DISCPORT_QUERY_STRING_REGEX = - Pattern.compile("discport=([0-9]{1,5})"); - - private final Endpoint endpoint; - - - - - public static DefaultPeer fromURI(final URI uri) { - checkNotNull(uri); - checkArgument("enode".equals(uri.getScheme())); - checkArgument(uri.getUserInfo() != null, "node id cannot be null"); - - // Process the peer's public key, in the host portion of the URI. - final BytesValue id = BytesValue.fromHexString(uri.getUserInfo()); - - // Process the host. If we have an IPv6 address in URL form translate to an address only form. - String host = uri.getHost(); - if (!InetAddresses.isInetAddress(host) && InetAddresses.isUriInetAddress(host)) { - host = InetAddresses.toAddrString(InetAddresses.forUriString(host)); - } - - // Process the ports; falling back to the default port in both TCP and UDP. - int tcpPort = DEFAULT_PORT; - int udpPort = DEFAULT_PORT; - if (NetworkUtility.isValidPort(uri.getPort())) { - tcpPort = udpPort = uri.getPort(); - } - - // If TCP and UDP ports differ, expect a query param 'discport' with the UDP port. - // See https://github.com/ethereum/wiki/wiki/enode-url-format - if (uri.getQuery() != null) { - udpPort = extractUdpPortFromQuery(uri.getQuery()).orElse(tcpPort); - } - - final Endpoint endpoint = new Endpoint(host, udpPort, OptionalInt.of(tcpPort)); - return new DefaultPeer(id, endpoint); - } - - /** - * Creates a {@link DefaultPeer} instance from its attributes, with a TCP port. - * - * @param id The node ID (public key). - * @param host Ip address. - * @param udpPort The UDP port. - * @param tcpPort The TCP port. - */ - public DefaultPeer(final BytesValue id, final String host, final int udpPort, final int tcpPort) { - this(id, host, udpPort, OptionalInt.of(tcpPort)); - } - - /** - * Creates a {@link DefaultPeer} instance from its attributes, without a TCP port. - * - * @param id The node ID (public key). - * @param host Ip address. - * @param udpPort UDP port. - */ - public DefaultPeer(final BytesValue id, final String host, final int udpPort) { - this(id, host, udpPort, OptionalInt.empty()); - } - - /** - * Creates a {@link DefaultPeer} instance from its attributes, without a TCP port. - * - * @param id The node ID (public key). - * @param host Ip address. - * @param udpPort the port number on which to communicate UDP traffic with the peer. - * @param tcpPort the port number on which to communicate TCP traffic with the peer. - */ - public DefaultPeer( - final BytesValue id, final String host, final int udpPort, final OptionalInt tcpPort) { - this(id, new Endpoint(host, udpPort,tcpPort)); - } - - /** - * Creates a {@link DefaultPeer} instance from its ID and its {@link Endpoint}. - * - * @param id The node ID (public key). - * @param endpoint The endpoint for this peer. - */ - public DefaultPeer(final BytesValue id, final Endpoint endpoint) { - super(id); - checkArgument( - id != null && id.size() == PEER_ID_SIZE, "id must be non-null and exactly 64 bytes long"); - checkArgument(endpoint != null, "endpoint cannot be null"); - this.endpoint = endpoint; - } - - /** - * Decodes the RLP stream as a Peer instance. - * - * @param in The RLP input stream from which to read. - * @return The decoded representation. - */ - public static Peer readFrom(final RLPInput in) { - final int size = in.enterList(); - - - // Subtract 1 from the total size of the list, to account for the peer ID which will be decoded - // by us. - final Endpoint endpoint = Endpoint.decodeInline(in, size - 1); - final BytesValue id = in.readBytesValue(); - in.leaveList(); - return new DefaultPeer(id, endpoint); - } - - private static Optional extractUdpPortFromQuery(final String query) { - final Matcher matcher = DISCPORT_QUERY_STRING_REGEX.matcher(query); - Optional answer = Optional.empty(); - if (matcher.matches()) { - answer = Optional.ofNullable(Ints.tryParse(matcher.group(1))); - } - return answer.filter(NetworkUtility::isValidPort); - } - - /** {@inheritDoc} */ - @Override - public Endpoint getEndpoint() { - return endpoint; - } - - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!(obj instanceof DefaultPeer)) { - return false; - } - final DefaultPeer other = (DefaultPeer) obj; - return id.equals(other.id) && endpoint.equals(other.endpoint); - } - - @Override - public int hashCode() { - return Objects.hash(id, endpoint); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DefaultPeer{"); - sb.append("id=").append(id); - sb.append(", endpoint=").append(endpoint); - sb.append('}'); - return sb.toString(); - } -} - diff --git a/src/main/java/io/xdag/discovery/peers/DefaultPeerId.java b/src/main/java/io/xdag/discovery/peers/DefaultPeerId.java deleted file mode 100644 index c3974927..00000000 --- a/src/main/java/io/xdag/discovery/peers/DefaultPeerId.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.discovery.peers; - -import io.xdag.utils.discoveryutils.cryto.Hash; -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.io.IOException; -import java.util.Objects; - -public class DefaultPeerId implements PeerId { - protected final BytesValue id; - private Bytes32 sha256; - - public DefaultPeerId(final BytesValue id) { - this.id = id; - } - - @Override - public BytesValue getId() { - return id; - } - - @Override - public Bytes32 sha256() throws IOException { - if (sha256 == null) { - sha256 = Hash.sha256(getId()); - } - return sha256; - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || o.getClass().isAssignableFrom(this.getClass())) return false; - final DefaultPeerId that = (DefaultPeerId) o; - return Objects.equals(id, that.id); - } - - @Override - public int hashCode() { - return Objects.hash(id); - } -} diff --git a/src/main/java/io/xdag/discovery/peers/DiscoveryPeer.java b/src/main/java/io/xdag/discovery/peers/DiscoveryPeer.java deleted file mode 100755 index 8002df46..00000000 --- a/src/main/java/io/xdag/discovery/peers/DiscoveryPeer.java +++ /dev/null @@ -1,122 +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.discovery.peers;/* - * Copyright 2018 ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ - - -import io.xdag.utils.discoveryutils.PeerDiscoveryStatus; -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.util.OptionalInt; - - -/** - * Represents an Ethereum node that we interacting with through the discovery and wire protocols. - */ -public class DiscoveryPeer extends DefaultPeer { - private PeerDiscoveryStatus status = PeerDiscoveryStatus.KNOWN; - - // Timestamps. - private long firstDiscovered = 0; - private long lastContacted = 0; - private long lastSeen = 0; - - - public DiscoveryPeer( - final BytesValue id, final String host, final int udpPort, final int tcpPort) { - super(id, host, udpPort, tcpPort); - } - - public DiscoveryPeer( - final BytesValue id, final String host, final int udpPort, final OptionalInt tcpPort) { - super(id, host, udpPort, tcpPort); - } - - public DiscoveryPeer(final BytesValue id, final String host, final int udpPort) { - super(id, host, udpPort); - } - - public DiscoveryPeer(final BytesValue id, final Endpoint endpoint) { - super(id, endpoint); - } - - public DiscoveryPeer(final Peer peer) { - super(peer.getId(), peer.getEndpoint()); - } - - public PeerDiscoveryStatus getStatus() { - return status; - } - - public void setStatus(final PeerDiscoveryStatus status) { - this.status = status; - } - - public long getFirstDiscovered() { - return firstDiscovered; - } - - public PeerId setFirstDiscovered(final long firstDiscovered) { - this.firstDiscovered = firstDiscovered; - return this; - } - - public long getLastContacted() { - return lastContacted; - } - - public void setLastContacted(final long lastContacted) { - this.lastContacted = lastContacted; - } - - public long getLastSeen() { - return lastSeen; - } - - public void setLastSeen(final long lastSeen) { - this.lastSeen = lastSeen; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DiscoveryPeer{"); - sb.append("status=").append(status); - sb.append(", endPoint=").append(this.getEndpoint()); - sb.append(", firstDiscovered=").append(firstDiscovered); - sb.append(", lastContacted=").append(lastContacted); - sb.append(", lastSeen=").append(lastSeen); - sb.append('}'); - return sb.toString(); - } -} diff --git a/src/main/java/io/xdag/discovery/peers/Endpoint.java b/src/main/java/io/xdag/discovery/peers/Endpoint.java deleted file mode 100755 index d9988c77..00000000 --- a/src/main/java/io/xdag/discovery/peers/Endpoint.java +++ /dev/null @@ -1,174 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.NetworkUtility; -import io.xdag.utils.discoveryutils.PeerDiscoveryPacketDecodingException; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; -import com.google.common.net.InetAddresses; - -import java.net.InetAddress; -import java.util.Objects; -import java.util.OptionalInt; - -import static io.xdag.utils.discoveryutils.Preconditions.checkGuard; -import static com.google.common.base.Preconditions.checkArgument; - - -public class Endpoint { - private final String host; - private final int udpPort; - private final OptionalInt tcpPort; - - public Endpoint(final String host, final int udpPort, final OptionalInt tcpPort) { - checkArgument( - host != null && InetAddresses.isInetAddress(host), "host requires a valid IP address"); - checkArgument( - NetworkUtility.isValidPort(udpPort), "UDP port requires a value between 1 and 65535"); - tcpPort.ifPresent( - p -> - checkArgument( - NetworkUtility.isValidPort(p), "TCP port requires a value between 1 and 65535")); - - this.host = host; - this.udpPort = udpPort; - this.tcpPort = tcpPort; - } - - public String getHost() { - return host; - } - - public int getUdpPort() { - return udpPort; - } - - public OptionalInt getTcpPort() { - return tcpPort; - } - - @Override - public boolean equals(final Object obj) { - if (obj == null) { - return false; - } - if (obj == this) { - return true; - } - if (!(obj instanceof Endpoint)) { - return false; - } - final Endpoint other = (Endpoint) obj; - return host.equals(other.host) - && this.udpPort == other.udpPort - && (this.tcpPort.equals(other.tcpPort)); - } - - @Override - public int hashCode() { - return Objects.hash(host, udpPort, tcpPort); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("Endpoint{"); - sb.append("host='").append(host).append('\''); - sb.append(", udpPort=").append(udpPort); - tcpPort.ifPresent(p -> sb.append(", getTcpPort=").append(p)); - sb.append('}'); - return sb.toString(); - } - - /** - * Encodes this endpoint into a standalone object. - * - * @param out The RLP output stream. - */ - public void encodeStandalone(final RLPOutput out) { - out.startList(); - encodeInline(out); - out.endList(); - } - - /** - * Encodes this endpoint to an RLP representation that is inlined into a containing object - * (generally a Peer). - * - * @param out The RLP output stream. - */ - public void encodeInline(final RLPOutput out) { - out.writeInetAddress(InetAddresses.forString(host)); - out.writeUnsignedShort(udpPort); - if (tcpPort.isPresent()) { - out.writeUnsignedShort(tcpPort.getAsInt()); - } else { - out.writeNull(); - } - } - - /** - * Decodes the input stream as an Endpoint instance appearing inline within another object - * (generally a Peer). - * - * @param fieldCount The number of fields RLP list. - * @param in The RLP input stream from which to read. - * @return The decoded endpoint. - */ - public static Endpoint decodeInline(final RLPInput in, final int fieldCount) { - checkGuard( - fieldCount == 2 || fieldCount == 3, - PeerDiscoveryPacketDecodingException::new, - "Invalid number of components in RLP representation of an endpoint: expected 2 o 3 elements but got %s", - fieldCount); - - final InetAddress addr = in.readInetAddress(); - final int udpPort = in.readUnsignedShort(); - - // Some mainnet packets have been shown to either not have the TCP port field at all, - // or to have an RLP NULL value for it. - OptionalInt tcpPort = OptionalInt.empty(); - if (fieldCount == 3) { - if (in.nextIsNull()) { - in.skipNext(); - } else { - tcpPort = OptionalInt.of(in.readUnsignedShort()); - } - } - return new Endpoint(addr.getHostAddress(), udpPort, tcpPort); - } - - /** - * Decodes the RLP stream as a standalone Endpoint instance, which is not part of a Peer. - * - * @param in The RLP input stream from which to read. - * @return The decoded endpoint. - */ - public static Endpoint decodeStandalone(final RLPInput in) { - final int size = in.enterList(); - final Endpoint endpoint = decodeInline(in, size); - in.leaveList(); - return endpoint; - } -} diff --git a/src/main/java/io/xdag/discovery/peers/Peer.java b/src/main/java/io/xdag/discovery/peers/Peer.java deleted file mode 100644 index ee76e3bb..00000000 --- a/src/main/java/io/xdag/discovery/peers/Peer.java +++ /dev/null @@ -1,57 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.RLPOutput; - -import java.security.SecureRandom; - -public interface Peer extends PeerId{ - Endpoint getEndpoint(); - - /** - * Generates a random peer ID in a secure manner. - * - * @return The generated peer ID. - */ - static BytesValue randomId() { - final byte[] id = new byte[37]; -// final byte[] id = new byte[34]; - new SecureRandom().nextBytes(id); - return BytesValue.wrap(id); - } - - /** - * Encodes this peer to its RLP representation. - * - * @param out The RLP output stream to which to write. - */ - default void writeTo(final RLPOutput out) { - out.startList(); - getEndpoint().encodeInline(out); - out.writeBytesValue(getId()); - out.endList(); - } -} diff --git a/src/main/java/io/xdag/discovery/peers/PeerBlacklist.java b/src/main/java/io/xdag/discovery/peers/PeerBlacklist.java deleted file mode 100644 index c0902aa2..00000000 --- a/src/main/java/io/xdag/discovery/peers/PeerBlacklist.java +++ /dev/null @@ -1,89 +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.discovery.peers; - - - -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -//todo -public class PeerBlacklist { - private static final int DEFAULT_BLACKLIST_CAP = 500; - - - - private final int blacklistCap; - private final Set blacklistedNodeIds = - Collections.synchronizedSet( - Collections.newSetFromMap( - new LinkedHashMap(20, 0.75f, true) { - @Override - protected boolean removeEldestEntry(final Map.Entry eldest) { - return size() > blacklistCap; - } - })); - - /** These nodes are always banned for the life of this list. They are not subject to rollover. */ - private final Set bannedNodeIds; - - public PeerBlacklist(final int blacklistCap, final Set bannedNodeIds) { - this.blacklistCap = blacklistCap; - this.bannedNodeIds = bannedNodeIds; - } - - public PeerBlacklist(final int blacklistCap) { - this(blacklistCap, Collections.emptySet()); - } - - public PeerBlacklist(final Set bannedNodeIds) { - this(DEFAULT_BLACKLIST_CAP, bannedNodeIds); - } - - public PeerBlacklist() { - this(DEFAULT_BLACKLIST_CAP, Collections.emptySet()); - } - - private boolean contains(final BytesValue nodeId) { - return blacklistedNodeIds.contains(nodeId) || bannedNodeIds.contains(nodeId); - } - - - public boolean contains(final Peer peer) { - return contains(peer.getId()); - } - - public void add(final Peer peer) { - add(peer.getId()); - } - - public void add(final BytesValue peerId) { - blacklistedNodeIds.add(peerId); - } - - -} \ No newline at end of file diff --git a/src/main/java/io/xdag/discovery/peers/PeerDistanceCalculator.java b/src/main/java/io/xdag/discovery/peers/PeerDistanceCalculator.java deleted file mode 100644 index d4e9a6ab..00000000 --- a/src/main/java/io/xdag/discovery/peers/PeerDistanceCalculator.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.discovery.peers; - -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.util.Arrays; - -public class PeerDistanceCalculator { - - /** - * Calculates the XOR distance between two values. - * - * @param v1 the first value - * @param v2 the second value - * @return the distance - */ - static int distance(final BytesValue v1, final BytesValue v2) { - assert (v1.size() == v2.size()); - final byte[] v1b = v1.extractArray(); - final byte[] v2b = v2.extractArray(); - if (Arrays.equals(v1b, v2b)) { - return 0; - } - int distance = v1b.length * 8; - for (int i = 0; i < v1b.length; i++) { - final byte xor = (byte) (0xff & (v1b[i] ^ v2b[i])); - if (xor == 0) { - distance -= 8; - } else { - int p = 7; - while (((xor >> p--) & 0x01) == 0) { - distance--; - } - break; - } - } - return distance; - } -} diff --git a/src/main/java/io/xdag/discovery/peers/PeerId.java b/src/main/java/io/xdag/discovery/peers/PeerId.java deleted file mode 100644 index 0ba5c5cf..00000000 --- a/src/main/java/io/xdag/discovery/peers/PeerId.java +++ /dev/null @@ -1,41 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.io.IOException; - -public interface PeerId { - BytesValue getId(); - - /** - * The sha256-256 hash value of the peer's ID. The value may be memoized to avoid recomputation - * overhead. - * - * @return The sha-256 hash of the peer's ID. - */ - Bytes32 sha256() throws IOException; -} diff --git a/src/main/java/io/xdag/discovery/peers/PeerTable.java b/src/main/java/io/xdag/discovery/peers/PeerTable.java deleted file mode 100755 index e02d0f41..00000000 --- a/src/main/java/io/xdag/discovery/peers/PeerTable.java +++ /dev/null @@ -1,257 +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.discovery.peers; - -import io.xdag.utils.discoveryutils.PeerDiscoveryStatus; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import com.google.common.hash.BloomFilter; -import io.xdag.utils.discoveryutils.cryto.Hash; -import lombok.extern.slf4j.Slf4j; - -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ForkJoinPool; -import java.util.stream.Stream; - -import static java.util.Comparator.comparingInt; -import static java.util.stream.Collectors.toList; -import static io.xdag.discovery.peers.PeerDistanceCalculator.distance; - -@Slf4j -public class PeerTable { - private static final int N_BUCKETS = 256; - private static final int DEFAULT_BUCKET_SIZE = 16; - private static final int BLOOM_FILTER_REGENERATION_THRESHOLD = 50; // evictions - - private final Bucket[] table; - private final BytesValue sha256; - private final int maxEntriesCnt; - private final Map distanceCache; - private int evictionCnt = 0; - - /** - * Builds a new peer table, where distance is calculated using the provided nodeId as a baseline. - * - * @param nodeId The ID of the node where this peer table is stored. - * @param bucketSize The maximum length of each k-bucket. - */ - public PeerTable(final BytesValue nodeId, final int bucketSize) throws IOException { - this.sha256 = Hash.sha256(nodeId); - this.table = - Stream.generate(() -> new Bucket(DEFAULT_BUCKET_SIZE)) - .limit(N_BUCKETS + 1) - .toArray(Bucket[]::new); - this.distanceCache = new ConcurrentHashMap<>(); - this.maxEntriesCnt = N_BUCKETS * bucketSize; - - // A bloom filter with 4096 expected insertions of 64-byte keys with a 0.1% false positive - // probability yields a memory footprint of ~7.5kb. - //buildBloomFilter(); - } - - public PeerTable(final BytesValue nodeId) throws IOException { - this(nodeId, DEFAULT_BUCKET_SIZE); - } - - /** - * Returns the table's representation of a peer, if it exists. - * - * @param peer The peer to query. - * @return The stored representation. - */ - public Optional get(final PeerId peer) throws IOException { - final int distance = distanceFrom(peer); - return table[distance].getAndTouch(peer.getId()); - } - - /** - * Attempts to add the provided peer to the peer table, and returns an {@link AddResult} - * signalling one of three outcomes. - * - *

Possible outcomes:

- * - *
    - *
  • the operation succeeded and the peer was added to the corresponding k-bucket. - *
  • the operation failed because the k-bucket was full, in which case a candidate is proposed - * for eviction. - *
  • the operation failed because the peer already existed. - *
- * - * @see AddResult.Outcome - * @param peer The peer to add. - * @return An object indicating the outcome of the operation. - */ - public AddResult tryAdd(final DiscoveryPeer peer) throws IOException { - - final BytesValue id = peer.getId(); - final int distance = distanceFrom(peer); - - // Safeguard against adding ourselves to the peer table. - if (distance == 0) { - return AddResult.self(); - } - - final Bucket bucket = table[distance]; - // We add the peer, and two things can happen: (1) either we get an empty optional (peer was - // added successfully, - // or it was already there), or (2) we get a filled optional, in which case the bucket is full - // and an eviction - // candidate is proposed. The Bucket#add method will raise an exception if the peer already - // existed. - final Optional res; - try { - res = bucket.add(peer); - } catch (final IllegalArgumentException ex) { - return AddResult.existed(); - } - - if (!res.isPresent()) { - distanceCache.put(id, distance); - log.info("distanceCache.size = {}",distanceCache.size()); - return AddResult.added(); - } - - return res.map(AddResult::bucketFull).get(); - } - - /** - * Evicts a peer from the underlying table. - * - * @param peer The peer to evict. - */ - public void evict(final PeerId peer) throws IOException { - final BytesValue id = peer.getId(); - final int distance = distanceFrom(peer); - distanceCache.remove(id); - - final boolean evicted = table[distance].evict(peer); - evictionCnt += evicted ? 1 : 0; - - // Trigger the bloom filter regeneration if needed. - if (evictionCnt >= BLOOM_FILTER_REGENERATION_THRESHOLD) { - ForkJoinPool.commonPool().execute(this::buildBloomFilter); - } - - } - //BloomFilter判断id是否存在 - private void buildBloomFilter() { - final BloomFilter bf = - BloomFilter.create((id, val) -> val.putBytes(id.extractArray()), maxEntriesCnt, 0.001); - getAllPeers().stream().map(Peer::getId).forEach(bf::put); - this.evictionCnt = 0; - } - - /** - * Returns the limit peers (at most) closest to the provided target, based on the XOR - * distance between the sha-256 hash of the ID and the sha-256 hash of the target. - * - * @param target The target node ID. - * @param limit The amount of results to return. - * @return The limit closest peers, at most. - */ - public List nearestPeers(final BytesValue target, final int limit) throws IOException { - final BytesValue sha256 = Hash.sha256(target); - return getAllPeers() - .stream() - .filter(p -> p.getStatus() == PeerDiscoveryStatus.BONDED) - .sorted(comparingInt((peer) -> { - try { - return distance(peer.sha256(), sha256); - } catch (IOException e) { - e.printStackTrace(); - } - return 0; - })) - .limit(limit) - .collect(toList()); - } - - public Collection getAllPeers() { - return Arrays.stream(table).flatMap(e -> e.peers().stream()).collect(java.util.stream.Collectors.toUnmodifiableList()); - } - - /** - * Calculates the XOR distance between the sha-256 hashes of our node ID and the provided - * {@link DiscoveryPeer}. - * - * @param peer The target peer. - * @return The distance. - */ - private int distanceFrom(final PeerId peer) throws IOException { - final Integer distance = distanceCache.get(peer.getId()); - return distance == null ? distance(sha256, peer.sha256()) : distance; - } - - /** A class that encapsulates the result of a peer addition to the table. */ - public static class AddResult { - /** The outcome of the operation. */ - public enum Outcome { - - /** The peer was added successfully to its corresponding k-bucket. */ - ADDED, - - /** The bucket for this peer was full. An eviction candidate must be proposed. */ - BUCKET_FULL, - - /** The peer already existed, hence it was not overwritten. */ - ALREADY_EXISTED, - - /** The caller requested to add ourselves. */ - SELF - } - - private final Outcome outcome; - private final Peer evictionCandidate; - - private AddResult(final Outcome outcome, final Peer evictionCandidate) { - this.outcome = outcome; - this.evictionCandidate = evictionCandidate; - } - - static AddResult added() { - return new AddResult(Outcome.ADDED, null); - } - //bucket满的时候去除最后一位 - static AddResult bucketFull(final Peer evictionCandidate) { - return new AddResult(Outcome.BUCKET_FULL, evictionCandidate); - } - - static AddResult existed() { - return new AddResult(Outcome.ALREADY_EXISTED, null); - } - - static AddResult self() { - return new AddResult(Outcome.SELF, null); - } - - public Outcome getOutcome() { - return outcome; - } - - public Peer getEvictionCandidate() { - return evictionCandidate; - } - } -} diff --git a/src/main/java/io/xdag/libp2p/P2PNetwork.java b/src/main/java/io/xdag/libp2p/P2PNetwork.java deleted file mode 100644 index 0ac24a35..00000000 --- a/src/main/java/io/xdag/libp2p/P2PNetwork.java +++ /dev/null @@ -1,75 +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.libp2p; - -import io.xdag.libp2p.peer.NodeId; -import io.xdag.libp2p.peer.PeerAddress; -import io.xdag.utils.SafeFuture; -import org.apache.tuweni.bytes.Bytes; - -import java.util.Optional; -import java.util.stream.Stream; - -public interface P2PNetwork

{ - - void dail(String peer); - - enum State { - IDLE, - RUNNING, - STOPPED - } - - - - PeerAddress createPeerAddress(String peerAddress); - - boolean isConnected(PeerAddress peerAddress); - - Bytes getPrivateKey(); - - Optional getPeer(NodeId id); - - Stream streamPeers(); - - NodeId parseNodeId(final String nodeId); - - int getPeerCount(); - - String getNodeAddress(); - - NodeId getNodeId(); - - - - /** - * Starts the P2P network layer. - * - */ - SafeFuture start(); - - /** Stops the P2P network layer. */ - SafeFuture stop(); -} - diff --git a/src/main/java/io/xdag/libp2p/RPCHandler/BlockHandler.java b/src/main/java/io/xdag/libp2p/RPCHandler/BlockHandler.java deleted file mode 100644 index ee06fb3f..00000000 --- a/src/main/java/io/xdag/libp2p/RPCHandler/BlockHandler.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.libp2p.RPCHandler; - -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.crypto.jni.Native; -import io.xdag.libp2p.Libp2pChannel; -import io.xdag.libp2p.message.MessageQueueLib; -import io.xdag.net.message.Message; -import io.xdag.net.message.MessageFactory; -import io.xdag.net.message.impl.NewBlockMessage; -import io.xdag.utils.BytesUtils; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; - -import static io.xdag.core.XdagField.FieldType.XDAG_FIELD_HEAD_TEST; -import static io.xdag.utils.BasicUtils.crc32Verify; - -@EqualsAndHashCode(callSuper = false) -@Slf4j -@Data -public class BlockHandler extends ByteToMessageCodec { - private final Libp2pChannel libp2pChannel; - MessageFactory messageFactory; - MessageQueueLib msgQueue; - private boolean MainNet = false; - - public BlockHandler(Libp2pChannel libp2pChannel) { - this.libp2pChannel = libp2pChannel; - } - - /** 获取第i个的第n个字节 */ - public static byte getMsgcode(XdagBlock xdagblock, int n) { - byte[] data = xdagblock.getData(); - long type = BytesUtils.bytesToLong(data, 8, true); - - return (byte) (type >> (n << 2) & 0xf); - } - /* T 加解密的过程outbound应该先用上一次结束后的值 发完才加 */ - /**出去的最后一道*/ - @Override - protected void encode( - ChannelHandlerContext channelHandlerContext, XdagBlock xdagblock, ByteBuf out) { - byte[] uncryptData = xdagblock.getData(); - - byte[] encryptData = Native.dfslib_encrypt_byte_sector(uncryptData, uncryptData.length, - libp2pChannel.getNode().getStat().Outbound.get() + 1); - out.writeBytes(encryptData); - libp2pChannel.getNode().getStat().Outbound.add(); - } - /**进来的第一道*/ - @Override - protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List out) throws Exception { - log.debug("DragBlockHandler readableBytes " + in.readableBytes() + " bytes"); - if (in.readableBytes() >= XdagBlock.XDAG_BLOCK_SIZE) { - log.trace("Decoding packet (" + in.readableBytes() + " bytes)"); - byte[] encryptData = new byte[512]; - in.readBytes(encryptData); - byte[] uncryptData = Native.dfslib_uncrypt_byte_sector(encryptData, encryptData.length, - libp2pChannel.getNode().getStat().Inbound.get() + 1); - // 该通道的输入记录加一 - libp2pChannel.getNode().getStat().Inbound.add(); - // TODO:处理xdagblock的传输头 - long transportHeader = BytesUtils.bytesToLong(uncryptData, 0, true); - int ttl = (int) ((transportHeader >> 8) & 0xff); - long dataLength = (transportHeader >> 16 & 0xffff); - // crc校验码 - int crc = BytesUtils.bytesToInt(uncryptData, 4, true); - // 清除transportheader - System.arraycopy(BytesUtils.longToBytes(0, true), 0, uncryptData, 4, 4); - - // 验证长度和crc校验 - if (dataLength != 512 || !crc32Verify(uncryptData, crc)) { - log.debug(dataLength + " length"); - log.debug("receive not block verify error!"); - } - - 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; - // 普通区块 - XdagField.FieldType netType = MainNet ? XdagField.FieldType.XDAG_FIELD_HEAD : XDAG_FIELD_HEAD_TEST; - if (netType.asByte() == first_field_type) { - msg = new NewBlockMessage(xdagBlock, ttl); - } - // 消息区块 - 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"); - } - } -} diff --git a/src/main/java/io/xdag/libp2p/RPCHandler/RPCHandler.java b/src/main/java/io/xdag/libp2p/RPCHandler/RPCHandler.java deleted file mode 100644 index 1dff925c..00000000 --- a/src/main/java/io/xdag/libp2p/RPCHandler/RPCHandler.java +++ /dev/null @@ -1,339 +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.libp2p.RPCHandler; - -import com.google.common.util.concurrent.SettableFuture; -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.netty.channel.SimpleChannelInboundHandler; -import io.xdag.Kernel; -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.libp2p.Libp2pChannel; -import io.xdag.libp2p.manager.ChannelManager; -import io.xdag.libp2p.message.MessageQueueLib; -import io.xdag.net.XdagVersion; -import io.xdag.net.handler.MessageCodes; -import io.xdag.net.handler.Xdag; -import io.xdag.net.message.AbstractMessage; -import io.xdag.net.message.Message; -import io.xdag.net.message.impl.*; -import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.concurrent.CompletableFuture; - -@Slf4j -public class RPCHandler implements ProtocolBinding { - Controller controller; - Kernel kernel; - Libp2pChannel libp2pChannel; - BlockHandler blockHandler; - ChannelManager channelManager; - public RPCHandler(Kernel kernel) { - this.kernel = kernel; - this.channelManager = kernel.getLibp2pChannelManager(); - } - @NotNull - @Override - public ProtocolDescriptor getProtocolDescriptor() { - return new ProtocolDescriptor("xdagj"); - } - - @NotNull - @Override - public CompletableFuture initChannel(@NotNull P2PChannel p2PChannel, @NotNull String s) { - log.info("libp2p initChannel"); - final Connection connection = ((io.libp2p.core.Stream) p2PChannel).getConnection(); - libp2pChannel = new Libp2pChannel(connection,this); - libp2pChannel.init(); - channelManager.add(libp2pChannel); - blockHandler = new BlockHandler(libp2pChannel); - blockHandler.setMessageFactory(new Xdag03MessageFactory()); - channelManager.onChannelActive(libp2pChannel,libp2pChannel.getNode()); - blockHandler.setMsgQueue(new MessageQueueLib(libp2pChannel)); - MessageCodes messageCodes = new MessageCodes(); - this.controller = new Controller(kernel,libp2pChannel,blockHandler); - p2PChannel.pushHandler(blockHandler); - p2PChannel.pushHandler(messageCodes); - p2PChannel.pushHandler(controller); - return controller.activeFuture; - } - public Controller getController(){ - return controller; - } - - public static class Controller extends SimpleChannelInboundHandler implements Xdag{ - protected final CompletableFuture activeFuture = new CompletableFuture<>(); - protected Blockchain blockchain; - protected SyncManager syncMgr; - protected Kernel kernel; - protected Libp2pChannel channel; - protected MessageQueueLib msgQueue; - protected ChannelManager channelManager; - public Controller(Kernel kernel,Libp2pChannel channel,BlockHandler blockHandler) { - this.kernel = kernel; - this.channel = channel; - this.blockchain = kernel.getBlockchain(); - this.msgQueue = blockHandler.msgQueue; - this.syncMgr = kernel.getSyncMgr(); - this.channelManager = kernel.getChannelManager(); - } - - @Override - public void channelActive(ChannelHandlerContext ctx){ - log.info("channelActive and remove channel"); - ctx.close().addListener(future -> channelManager.remove(channel)); - } - /**进来的最后一道,而且发送不在这处理*/ - - @Override - protected void channelRead0(ChannelHandlerContext ctx, Message msg) { - switch (msg.getCommand()) { - case NEW_BLOCK: - processNewBlock((NewBlockMessage) msg); - break; - case BLOCK_REQUEST: - processBlockRequest((BlockRequestMessage) msg); - break; - case BLOCKS_REQUEST: - processBlocksRequest((BlocksRequestMessage) msg); - break; - case BLOCKS_REPLY: - processBlocksReply((BlocksReplyMessage) msg); - break; - case SUMS_REQUEST: - processSumsRequest((SumRequestMessage) msg); - break; - case SUMS_REPLY: - processSumsReply((SumReplyMessage) msg); - break; - case BLOCKEXT_REQUEST: - processBlockExtRequest((BlockExtRequestMessage) msg); - break; - default: - break; - } - } - - @Override - public void handlerAdded(ChannelHandlerContext ctx) { - log.info("handlerAdded "); - msgQueue.activate(ctx); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) { - log.debug("channelInactive:[{}] ", ctx.toString()); - this.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().getHexId()); - disconnect(); - } - - public void killTimers() { - log.debug("msgQueue stop"); - msgQueue.close(); - } - - /** - * ********************** Message Processing * *********************** - */ - protected void processNewBlock(NewBlockMessage msg) { - Block block = msg.getBlock(); - log.info("processNewBlock:{}", Hex.toHexString(block.getHashLow())); - BlockWrapper bw = new BlockWrapper(block, msg.getTtl() - 1, channel.getNode()); - syncMgr.validateAndAddNewBlock(bw); - } - - /** - * 区块请求响应一个区块 并开启一个线程不断发送一段时间内的区块 * - */ - protected void processBlocksRequest(BlocksRequestMessage msg) { - log.debug("processBlocksRequest:" + msg); - updateXdagStats(msg); - long startTime = msg.getStarttime(); - long endTime = msg.getEndtime(); - long random = msg.getRandom(); - - List blocks = blockchain.getBlocksByTime(startTime, endTime); - for (Block block : blocks) { - sendNewBlock(block, 1); - } - sendMessage(new BlocksReplyMessage(startTime, endTime, random, kernel.getBlockchain().getXdagStats())); - } - - protected void processBlocksReply(BlocksReplyMessage msg) { -// log.debug("processBlocksReply:" + msg); - updateXdagStats(msg); - long randomSeq = msg.getRandom(); - SettableFuture sf = kernel.getSync().getBlocksRequestMap().get(randomSeq); - if (sf != null) { - sf.set(new byte[]{0}); - } - } - - /** - * 将sumRequest的后8个字段填充为自己的sum 修改type类型为reply 发送 - */ - protected void processSumsRequest(SumRequestMessage msg) { - log.debug("processSumsRequest:" + msg); - updateXdagStats(msg); - byte[] sums = new byte[256]; - kernel.getBlockStore().loadSum(msg.getStarttime(), msg.getEndtime(), sums); - SumReplyMessage reply = new SumReplyMessage(msg.getEndtime(), msg.getRandom(), kernel.getBlockchain().getXdagStats(), sums); - sendMessage(reply); - log.debug("processSumsRequest:" + 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) { - log.debug("processBlockRequest:" + msg); - byte[] find = new byte[32]; - byte[] hash = msg.getHash(); - hash = Arrays.reverse(hash); - System.arraycopy(hash, 8, find, 8, 24); - Block block = blockchain.getBlockByHash(find, true); - if (block != null) { - NewBlockMessage message = new NewBlockMessage(block, kernel.getConfig().getNodeSpec().getTTL()); - sendMessage(message); - } - } - - /** - * ********************** Message Sending * *********************** - */ - @Override - public void sendNewBlock(Block newBlock, int TTL) { - log.debug("sendNewBlock:" + Hex.toHexString(newBlock.getHashLow())); - NewBlockMessage msg = new NewBlockMessage(newBlock, TTL); - sendMessage(msg); - } - - @Override - public long sendGetBlocks(long startTime, long endTime) { -// log.debug("sendGetBlocks:[startTime={} endTime={}]", startTime, endTime); - BlocksRequestMessage msg = new BlocksRequestMessage(startTime, endTime, kernel.getBlockchain().getXdagStats()); - sendMessage(msg); - return msg.getRandom(); - } - - @Override - public boolean isIdle() { - return false; - } - - @Override - public long sendGetBlock(byte[] hash) { - log.debug("sendGetBlock:[{}]", Hex.toHexString(hash)); - BlockRequestMessage msg = new BlockRequestMessage(hash, kernel.getBlockchain().getXdagStats()); - sendMessage(msg); - return msg.getRandom(); - } - - @Override - public long sendGetSums(long startTime, long endTime) { -// log.debug("sendGetSums:startTime=[{}],endTime=[{}]", startTime, endTime); - SumRequestMessage msg = new SumRequestMessage(startTime, endTime, kernel.getBlockchain().getXdagStats()); - 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"); - } - - @Override - public XdagVersion getVersion() { - return null; - } - - @Override - public void disableBlocks() { - // TODO Auto-generated method stub - } - - @Override - public void enableBlocks() { - // TODO Auto-generated method stub - } - - @Override - public void onSyncDone(boolean done) { - // TODO Auto-generated method stub - } - - public void updateXdagStats(AbstractMessage message) { - XdagStats remoteXdagStats = message.getXdagStats(); - kernel.getBlockchain().getXdagStats().update(remoteXdagStats); - kernel.getNetDBMgr().updateNetDB(message.getNetDB()); - } - } -} diff --git a/src/main/java/io/xdag/libp2p/RPCHandler/XHandler.java b/src/main/java/io/xdag/libp2p/RPCHandler/XHandler.java deleted file mode 100644 index 26ce85c6..00000000 --- a/src/main/java/io/xdag/libp2p/RPCHandler/XHandler.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.libp2p.RPCHandler; - -import com.google.common.util.concurrent.SettableFuture; -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.libp2p.Libp2pChannel; -import io.xdag.libp2p.message.MessageQueueLib; -import io.xdag.net.XdagVersion; -import io.xdag.net.handler.Xdag; -import io.xdag.net.message.Message; -import io.xdag.net.message.XdagMessageCodes; -import io.xdag.net.message.impl.SumReplyMessage; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.extern.slf4j.Slf4j; - -import java.math.BigInteger; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; - -@EqualsAndHashCode(callSuper = false) -@Data -@Slf4j -public abstract class XHandler extends SimpleChannelInboundHandler implements Xdag { - protected Kernel kernel; - protected Blockchain blockchain; - protected XdagVersion version = XdagVersion.V03; - protected Libp2pChannel channel; - protected MessageQueueLib msgQueue; - protected Block bestKnownBlock; - protected BigInteger totalDifficulty; - protected SyncManager syncMgr; - protected SettableFuture> futureBlocks; - protected SettableFuture futureSum; - protected Queue> futureSumSublist = new LinkedList<>(); - @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/libp2p/manager/ChannelManager.java b/src/main/java/io/xdag/libp2p/manager/ChannelManager.java deleted file mode 100644 index 594eb5ef..00000000 --- a/src/main/java/io/xdag/libp2p/manager/ChannelManager.java +++ /dev/null @@ -1,127 +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.libp2p.manager; - -import io.xdag.core.BlockWrapper; -import io.xdag.libp2p.Libp2pChannel; -import io.xdag.net.node.Node; -import lombok.extern.slf4j.Slf4j; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; - -@Slf4j -public class ChannelManager { - protected ConcurrentHashMap channels = new ConcurrentHashMap<>(); - protected ConcurrentHashMap activeChannels = new ConcurrentHashMap<>(); - /** Queue with new blocks from other peers */ - private final BlockingQueue newForeignBlocks = new LinkedBlockingQueue<>(); - // 广播区块 - private final Thread blockDistributeThread; - - public ChannelManager( ) { - this.blockDistributeThread = new Thread(this::newBlocksDistributeLoop, "NewSyncThreadBlocks"); - blockDistributeThread.start(); - } - - private void newBlocksDistributeLoop() { - while (!Thread.currentThread().isInterrupted()) { - BlockWrapper wrapper = null; - try { - wrapper = newForeignBlocks.take(); - sendNewBlock(wrapper); - } catch (InterruptedException e) { - break; - } catch (Throwable e) { - if (wrapper != null) { - log.error("Block dump: {}", wrapper.getBlock()); - } else { - log.error("Error broadcasting unknown block", e); - } - } - } - } - - public void sendNewBlock(BlockWrapper blockWrapper) { - - Node receive = null; - // 说明是自己产生的 - if (blockWrapper.getRemoteNode() != null) { - Libp2pChannel receiveChannel = activeChannels.get(blockWrapper.getRemoteNode().getHexId()); - receive = receiveChannel != null ? receiveChannel.getNode() : null; - } - //广播 - for (Libp2pChannel channel : activeChannels.values()) { - if (receive != null && channel.getNode().getHexId().equals(receive.getHexId())) { - log.debug("不发送给他"); - continue; - } - log.debug("发送给除receive的节点"); - channel.sendNewBlock(blockWrapper); - } - } - public void onChannelActive(Libp2pChannel channel, Node node){ - channel.setActive(true); - activeChannels.put(node.getHexId(), channel); - log.info("activeChannel size:"+ activeChannels.size()); - } - public void add(Libp2pChannel ch){ - channels.put(ch.getNode().getAddress(), ch); - } - - public void remove(Libp2pChannel ch) { - log.debug("Channel removed: remoteAddress = {}", ch.getIp()); - channels.remove(ch.getIp()); - if (ch.isActive()) { - activeChannels.remove(ch.getIp()); - ch.setActive(false); - } - } - - public void onNewForeignBlock(BlockWrapper blockWrapper) { - newForeignBlocks.add(blockWrapper); - } - - public List getactiveChannel(){ - Collection channels =activeChannels.values(); - log.debug("Active Channels {}", channels.size()); - return new ArrayList<>(activeChannels.values()); - } - public void stop() { - log.debug("Channel Manager stop..."); - if (blockDistributeThread != null) { - // 中断 - blockDistributeThread.interrupt(); - } - // 关闭所有连接 - for (Libp2pChannel channel : activeChannels.values()) { - channel.onDisconnect(); - } - } -} diff --git a/src/main/java/io/xdag/libp2p/message/MessageQueueLib.java b/src/main/java/io/xdag/libp2p/message/MessageQueueLib.java deleted file mode 100755 index e633b29e..00000000 --- a/src/main/java/io/xdag/libp2p/message/MessageQueueLib.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.libp2p.message; - -import io.netty.channel.ChannelFutureListener; -import io.netty.channel.ChannelHandlerContext; -import io.xdag.libp2p.Libp2pChannel; -import io.xdag.net.message.Message; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; - -import java.util.Queue; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - -@Slf4j -public class MessageQueueLib { - private static AtomicInteger cnt = new AtomicInteger(0); - boolean isRunning = false; - public static final ScheduledExecutorService timer = new ScheduledThreadPoolExecutor( - 4, - new BasicThreadFactory.Builder() - .namingPattern("MessageQueueTimer-" + cnt.getAndIncrement()) - .daemon(true) - .build()); - private ChannelHandlerContext ctx = null; - private final Queue requestQueue = new ConcurrentLinkedQueue<>(); - private final Queue respondQueue = new ConcurrentLinkedQueue<>(); - private ScheduledFuture timerTask; - private Libp2pChannel channel; - - public MessageQueueLib(Libp2pChannel channel) { - this.channel = channel; - } - public void activate(ChannelHandlerContext ctx) { - /**处理发送的区块*/ - this.ctx = ctx; - isRunning = true; - timerTask = timer.scheduleAtFixedRate( - () -> { - try { - nudgeQueue(); - } catch (Throwable t) { - log.error("Unhandled exception", t); - } - }, - 10, - 10, - // 10毫秒执行一次 - TimeUnit.MILLISECONDS); - } - /**发送区块*/ - private void nudgeQueue() { - // 1000 / 10 * 5 * 2 = 1000 messages per second - 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); - } - - } - ctx.flush(); - } - - public void sendMessage(Message msg) { - if (channel.isDisconnected()) { - log.warn("{}: attempt to send [{}] message after disconnect", channel, msg.getCommand().name()); - return; - } - - if (msg.getAnswerMessage() != null) { - requestQueue.add(msg); - } else { - respondQueue.add(msg); - } - } - - - - - public void disconnect() { - ctx.close(); - } - - public void close() { - isRunning = false; - if (timerTask != null) { - timerTask.cancel(false); - } - } - - public boolean isRunning() { - return isRunning; - } - - public boolean isIdle() { - return size() == 0; - } - - public int size() { - return requestQueue.size() + respondQueue.size(); - } -} diff --git a/src/main/java/io/xdag/net/Channel.java b/src/main/java/io/xdag/net/Channel.java new file mode 100644 index 00000000..dce56fd7 --- /dev/null +++ b/src/main/java/io/xdag/net/Channel.java @@ -0,0 +1,46 @@ +package io.xdag.net; + +import io.netty.channel.socket.nio.NioSocketChannel; +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; + +/** + * @author wawa + */ +public abstract class Channel { + protected NioSocketChannel socket; + protected InetSocketAddress inetSocketAddress; + /** 该channel对应的节点 */ + protected Node node; + + public abstract InetSocketAddress getInetSocketAddress(); + + public abstract void setActive(boolean b); + + public abstract boolean isActive(); + + public abstract Node getNode(); + + public abstract String getIp(); + + public abstract void sendNewBlock(BlockWrapper blockWrapper); + + public abstract void onDisconnect(); + + public abstract int getPort(); + + public abstract void dropConnection(); + + public abstract Xdag getXdag(); + + public abstract boolean isDisconnected(); + + public abstract MessageQueue getmessageQueue(); + + public abstract Kernel getKernel(); +} diff --git a/src/main/java/io/xdag/net/XdagChannel.java b/src/main/java/io/xdag/net/XdagChannel.java index 60360f65..e7bb6344 100644 --- a/src/main/java/io/xdag/net/XdagChannel.java +++ b/src/main/java/io/xdag/net/XdagChannel.java @@ -44,17 +44,19 @@ import io.xdag.net.node.Node; import java.net.InetSocketAddress; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; import org.bouncycastle.util.encoders.Hex; +@EqualsAndHashCode(callSuper = true) @Data @Slf4j -public class XdagChannel { +public class XdagChannel extends Channel { private final NioSocketChannel socket; private InetSocketAddress inetSocketAddress; private boolean isActive; private boolean isDisconnected = false; - private Kernel kernel; + protected Kernel kernel; /** 握手 密钥 */ private XdagHandshakeHandler handshakeHandler; @@ -103,7 +105,7 @@ public void initWithNode(final String host, final int port) { log.debug("Initwith Node host:" + host + " port:" + port + " node:" + node.getHexId()); } - public void notifyDisconnect(XdagChannel channel) { + public void notifyDisconnect(Channel channel) { log.debug("Node {}: notifies about disconnect", channel); channel.onDisconnect(); } @@ -117,22 +119,31 @@ public void onSyncDone(boolean done) { xdag.onSyncDone(done); } + @Override public String getIp() { return inetSocketAddress.getAddress().getHostAddress(); } + @Override public int getPort() { return inetSocketAddress.getPort(); } + @Override public void onDisconnect() { isDisconnected = true; } + @Override public boolean isDisconnected() { return isDisconnected; } + @Override + public MessageQueue getmessageQueue() { + return msgQueue; + } + public void sendPubkey(ChannelHandlerContext ctx) throws Exception { ByteBuf buffer = ctx.alloc().buffer(1024); buffer.writeBytes(kernel.getConfig().getNodeSpec().getXKeys().pub); @@ -147,6 +158,7 @@ public void sendPassword(ChannelHandlerContext ctx) throws Exception { node.getStat().Outbound.add(1); } + @Override public void sendNewBlock(BlockWrapper blockWrapper) { log.debug("send a block hash is {}", Hex.toHexString(blockWrapper.getBlock().getHashLow())); log.debug("ttl:" + blockWrapper.getTtl()); @@ -184,10 +196,12 @@ public String toString() { return format; } + @Override public Xdag getXdag() { return xdag; } + @Override public void dropConnection() { xdag.dropConnection(); } diff --git a/src/main/java/io/xdag/net/discovery/DiscoveryController.java b/src/main/java/io/xdag/net/discovery/DiscoveryController.java new file mode 100644 index 00000000..0e1aea01 --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/DiscoveryController.java @@ -0,0 +1,46 @@ +package io.xdag.net.discovery; + +import io.libp2p.core.crypto.KeyKt; +import io.libp2p.core.crypto.PrivKey; +import io.xdag.Kernel; +import io.xdag.net.discovery.discv5.DiscV5ServiceImpl; +import lombok.Getter; +import org.apache.tuweni.bytes.Bytes; + +import java.util.List; + +@Getter +public class DiscoveryController { + protected DiscoveryService discV5Service; + Kernel kernel; + String ip; + int port; + boolean isbootnode; + PrivKey privKey; + public DiscoveryController(Kernel kernel) { + this.kernel = kernel; + ip = kernel.getConfig().getNodeSpec().getNodeIp(); + port = kernel.getConfig().getNodeSpec().getLibp2pPort(); + isbootnode = kernel.getConfig().getNodeSpec().isBootnode(); + privKey = kernel.getPrivKey(); + } + + public void start(){ + if(kernel.getConfig().getNodeSpec().isBootnode()){ + String Privkey = kernel.getConfig().getNodeSpec().getLibp2pPrivkey(); + Bytes privkeybytes = Bytes.fromHexString(Privkey); + this.privKey = KeyKt.unmarshalPrivateKey(privkeybytes.toArrayUnsafe()); + }else{ + this.privKey = kernel.getPrivKey(); + } + List bootnodes = kernel.getConfig().getNodeSpec().getBootnodes(); + discV5Service = DiscV5ServiceImpl.create(Bytes.wrap(privKey.raw()),ip,port,bootnodes); + discV5Service.start(); + discV5Service.searchForPeers(); + + } + + public void stop() { + discV5Service.stop(); + } +} diff --git a/src/main/java/io/xdag/net/discovery/DiscoveryPeer.java b/src/main/java/io/xdag/net/discovery/DiscoveryPeer.java new file mode 100644 index 00000000..54669ef0 --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/DiscoveryPeer.java @@ -0,0 +1,47 @@ +package io.xdag.net.discovery; + +import com.google.common.base.MoreObjects; +import org.apache.tuweni.bytes.Bytes; + +import java.net.InetSocketAddress; +import java.util.Objects; + +/** + * @author wawa + */ +public record DiscoveryPeer(Bytes publicKey, InetSocketAddress nodeAddress) { + + public Bytes getPublicKey() { + return publicKey; + } + + public InetSocketAddress getNodeAddress() { + return nodeAddress; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final 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/discovery/DiscoveryService.java b/src/main/java/io/xdag/net/discovery/DiscoveryService.java new file mode 100644 index 00000000..f1cc9be7 --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/DiscoveryService.java @@ -0,0 +1,24 @@ +package io.xdag.net.discovery; + +import io.xdag.utils.SafeFuture; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author wawa + */ +public interface DiscoveryService { + + SafeFuture start(); + + SafeFuture stop(); + + Stream streamKnownPeers(); + + SafeFuture searchForPeers(); + + Optional getEnr(); + +} + diff --git a/src/main/java/io/xdag/net/discovery/discv5/DiscV5ServiceImpl.java b/src/main/java/io/xdag/net/discovery/discv5/DiscV5ServiceImpl.java new file mode 100644 index 00000000..847c89fc --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/discv5/DiscV5ServiceImpl.java @@ -0,0 +1,76 @@ +package io.xdag.net.discovery.discv5; + +import io.xdag.net.discovery.DiscoveryPeer; +import io.xdag.net.discovery.DiscoveryService; +import io.xdag.utils.SafeFuture; +import io.xdag.utils.Service; +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; +import org.ethereum.beacon.discovery.schema.NodeRecordInfo; +import org.ethereum.beacon.discovery.schema.NodeStatus; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author wawa + */ +public class DiscV5ServiceImpl extends Service implements DiscoveryService { + + private final DiscoverySystem discoverySystem; + + public DiscV5ServiceImpl(final DiscoverySystem discoverySystem) { + this.discoverySystem = discoverySystem; + } + + public static DiscoveryService 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 DiscV5ServiceImpl(discoveryManager); + } + + @Override + protected SafeFuture doStart() { + return SafeFuture.of(discoverySystem.start()); + } + + @Override + protected SafeFuture doStop() { + discoverySystem.stop(); + return SafeFuture.completedFuture(null); + } + + @Override + public Stream streamKnownPeers() { + return activeNodes().map(NodeRecordConverter::convertToDiscoveryPeer).flatMap(Optional::stream); + } + + @Override + public SafeFuture searchForPeers() { + return SafeFuture.of(discoverySystem.searchForNewPeers()); + } + + @Override + public Optional getEnr() { + return Optional.of(discoverySystem.getLocalNodeRecord().asEnr()); + } + + + private Stream activeNodes() { + return discoverySystem + .streamKnownNodes() + .filter(record -> record.getStatus() == NodeStatus.ACTIVE) + .map(NodeRecordInfo::getNode); + } +} diff --git a/src/main/java/io/xdag/net/discovery/discv5/NodeRecordConverter.java b/src/main/java/io/xdag/net/discovery/discv5/NodeRecordConverter.java new file mode 100644 index 00000000..c22387e9 --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/discv5/NodeRecordConverter.java @@ -0,0 +1,25 @@ +package io.xdag.net.discovery.discv5; + +import io.xdag.net.discovery.DiscoveryPeer; +import org.apache.tuweni.bytes.Bytes; +import org.ethereum.beacon.discovery.schema.EnrField; +import org.ethereum.beacon.discovery.schema.NodeRecord; + +import java.net.InetSocketAddress; +import java.util.Optional; + +/** + * @author wawa + */ +public class NodeRecordConverter { + static Optional convertToDiscoveryPeer(final NodeRecord nodeRecord) { + return nodeRecord + .getTcpAddress() + .map(address -> socketAddressToDiscoveryPeer(nodeRecord, address)); + } + + private static DiscoveryPeer socketAddressToDiscoveryPeer( + final NodeRecord nodeRecord, final InetSocketAddress address) { + return new DiscoveryPeer(((Bytes) nodeRecord.get(EnrField.PKEY_SECP256K1)), address); + } +} diff --git a/src/main/java/io/xdag/net/discovery/noop/NoOpDiscoveryServiceImpl.java b/src/main/java/io/xdag/net/discovery/noop/NoOpDiscoveryServiceImpl.java new file mode 100644 index 00000000..8e0bae5f --- /dev/null +++ b/src/main/java/io/xdag/net/discovery/noop/NoOpDiscoveryServiceImpl.java @@ -0,0 +1,40 @@ +package io.xdag.net.discovery.noop; + +import io.xdag.net.discovery.DiscoveryPeer; +import io.xdag.net.discovery.DiscoveryService; +import io.xdag.utils.SafeFuture; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author wawa + */ +public class NoOpDiscoveryServiceImpl implements DiscoveryService { + + @Override + public SafeFuture start() { + return SafeFuture.COMPLETE; + } + + @Override + public SafeFuture stop() { + return SafeFuture.COMPLETE; + } + + @Override + public Stream streamKnownPeers() { + return Stream.empty(); + } + + @Override + public SafeFuture searchForPeers() { + return SafeFuture.COMPLETE; + } + + @Override + public Optional getEnr() { + return Optional.empty(); + } + +} diff --git a/src/main/java/io/xdag/net/handler/Xdag03.java b/src/main/java/io/xdag/net/handler/Xdag03.java index 8e8178ed..20324d6a 100644 --- a/src/main/java/io/xdag/net/handler/Xdag03.java +++ b/src/main/java/io/xdag/net/handler/Xdag03.java @@ -29,6 +29,7 @@ import io.xdag.core.Block; import io.xdag.core.BlockWrapper; import io.xdag.core.XdagStats; +import io.xdag.net.Channel; import io.xdag.net.XdagChannel; import io.xdag.net.XdagVersion; import io.xdag.net.message.AbstractMessage; @@ -59,7 +60,7 @@ public Thread newThread(@Nonnull Runnable r) { private XdagVersion version = XdagVersion.V03; - public Xdag03(Kernel kernel, XdagChannel channel) { + public Xdag03(Kernel kernel, Channel channel) { this.kernel = kernel; this.channel = channel; this.blockchain = kernel.getBlockchain(); @@ -69,29 +70,29 @@ public Xdag03(Kernel kernel, XdagChannel channel) { @Override protected void channelRead0(ChannelHandlerContext ctx, Message msg) { switch (msg.getCommand()) { - case NEW_BLOCK: - processNewBlock((NewBlockMessage) msg); - break; - case BLOCK_REQUEST: - processBlockRequest((BlockRequestMessage) msg); - break; - case BLOCKS_REQUEST: - processBlocksRequest((BlocksRequestMessage) msg); - break; - case BLOCKS_REPLY: - processBlocksReply((BlocksReplyMessage) msg); - break; - case SUMS_REQUEST: - processSumsRequest((SumRequestMessage) msg); - break; - case SUMS_REPLY: - processSumsReply((SumReplyMessage) msg); - break; - case BLOCKEXT_REQUEST: - processBlockExtRequest((BlockExtRequestMessage) msg); - break; - default: - break; + case NEW_BLOCK: + processNewBlock((NewBlockMessage) msg); + break; + case BLOCK_REQUEST: + processBlockRequest((BlockRequestMessage) msg); + break; + case BLOCKS_REQUEST: + processBlocksRequest((BlocksRequestMessage) msg); + break; + case BLOCKS_REPLY: + processBlocksReply((BlocksReplyMessage) msg); + break; + case SUMS_REQUEST: + processSumsRequest((SumRequestMessage) msg); + break; + case SUMS_REPLY: + processSumsReply((SumReplyMessage) msg); + break; + case BLOCKEXT_REQUEST: + processBlockExtRequest((BlockExtRequestMessage) msg); + break; + default: + break; } } diff --git a/src/main/java/io/xdag/net/handler/XdagBlockHandler.java b/src/main/java/io/xdag/net/handler/XdagBlockHandler.java index 3d2919c5..a5a04d86 100644 --- a/src/main/java/io/xdag/net/handler/XdagBlockHandler.java +++ b/src/main/java/io/xdag/net/handler/XdagBlockHandler.java @@ -33,6 +33,7 @@ import io.xdag.core.XdagBlock; import io.xdag.core.XdagField; import io.xdag.crypto.jni.Native; +import io.xdag.net.Channel; import io.xdag.net.XdagChannel; import io.xdag.net.message.Message; import io.xdag.net.message.MessageFactory; @@ -46,10 +47,10 @@ @Slf4j @Data public class XdagBlockHandler extends ByteToMessageCodec { - private XdagChannel channel; + private Channel channel; private MessageFactory messageFactory; - public XdagBlockHandler(XdagChannel channel) { + public XdagBlockHandler(Channel channel) { this.channel = channel; } @@ -64,9 +65,16 @@ public static byte getMsgCode(XdagBlock xdagblock, int n) { protected void encode( ChannelHandlerContext channelHandlerContext, XdagBlock xdagblock, ByteBuf out) { byte[] unCryptData = xdagblock.getData(); - - byte[] encryptData = Native.dfslib_encrypt_byte_sector(unCryptData, unCryptData.length, - channel.getNode().getStat().Outbound.get() - 3 + 1); + byte[] encryptData ; + // libp2p没有三次握手 + if(channel.getClass().equals(XdagChannel.class)){ + encryptData = Native.dfslib_encrypt_byte_sector(unCryptData, unCryptData.length, + channel.getNode().getStat().Outbound.get() - 3 + 1); + } + else{ + encryptData = Native.dfslib_encrypt_byte_sector(unCryptData, unCryptData.length, + channel.getNode().getStat().Outbound.get() + 1); + } out.writeBytes(encryptData); channel.getNode().getStat().Outbound.add(); } @@ -77,8 +85,16 @@ protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, L log.trace("Decoding packet (" + in.readableBytes() + " bytes)"); byte[] encryptData = new byte[512]; in.readBytes(encryptData); - byte[] unCryptData = Native.dfslib_uncrypt_byte_sector(encryptData, encryptData.length, - channel.getNode().getStat().Inbound.get() - 3 + 1); + byte[] unCryptData ; + if(channel.getClass().equals(XdagChannel.class)){ + unCryptData = Native.dfslib_uncrypt_byte_sector(encryptData, encryptData.length, + channel.getNode().getStat().Inbound.get() - 3 + 1); + } + // libp2p没有三次握手 + else{ + unCryptData = Native.dfslib_uncrypt_byte_sector(encryptData, encryptData.length, + channel.getNode().getStat().Inbound.get() + 1); + } channel.getNode().getStat().Inbound.add(); // TODO:process xdagblock transport header diff --git a/src/main/java/io/xdag/net/handler/XdagHandler.java b/src/main/java/io/xdag/net/handler/XdagHandler.java index b0911887..717ec455 100644 --- a/src/main/java/io/xdag/net/handler/XdagHandler.java +++ b/src/main/java/io/xdag/net/handler/XdagHandler.java @@ -29,7 +29,7 @@ import io.xdag.consensus.SyncManager; import io.xdag.core.Block; import io.xdag.core.Blockchain; -import io.xdag.net.XdagChannel; +import io.xdag.net.Channel; import io.xdag.net.XdagVersion; import io.xdag.net.message.Message; import io.xdag.net.message.MessageQueue; @@ -46,7 +46,7 @@ public abstract class XdagHandler extends SimpleChannelInboundHandler i protected Kernel kernel; protected Blockchain blockchain; protected XdagVersion version = XdagVersion.V03; - protected XdagChannel channel; + protected Channel channel; protected MessageQueue msgQueue; protected Block bestKnownBlock; protected BigInteger totalDifficulty; diff --git a/src/main/java/io/xdag/net/libp2p/DiscoveryPeerToMultiaddrConverter.java b/src/main/java/io/xdag/net/libp2p/DiscoveryPeerToMultiaddrConverter.java new file mode 100644 index 00000000..a8ef7370 --- /dev/null +++ b/src/main/java/io/xdag/net/libp2p/DiscoveryPeerToMultiaddrConverter.java @@ -0,0 +1,38 @@ +package io.xdag.net.libp2p; + +import io.libp2p.core.PeerId; +import io.libp2p.core.crypto.PubKey; +import io.libp2p.core.multiformats.Multiaddr; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import io.xdag.net.discovery.DiscoveryPeer; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import static io.libp2p.crypto.keys.Secp256k1Kt.unmarshalSecp256k1PublicKey; + +public class DiscoveryPeerToMultiaddrConverter { + + public static Multiaddr convertToMultiAddr(final DiscoveryPeer peer) { + final InetSocketAddress address = peer.getNodeAddress(); + final LibP2PNodeId nodeId = getNodeId(peer); + final String addrString = + String.format( + "/%s/%s/tcp/%d/p2p/%s", + protocol(address.getAddress()), + address.getAddress().getHostAddress(), + address.getPort(), + nodeId); + return Multiaddr.fromString(addrString); + } + + public static LibP2PNodeId getNodeId(final DiscoveryPeer peer) { + final PubKey pubKey = unmarshalSecp256k1PublicKey(peer.getPublicKey().toArrayUnsafe()); + return new LibP2PNodeId(PeerId.fromPubKey(pubKey)); + } + + private static String protocol(final InetAddress address) { + return address instanceof Inet6Address ? "ip6" : "ip4"; + } +} diff --git a/src/main/java/io/xdag/libp2p/Libp2pChannel.java b/src/main/java/io/xdag/net/libp2p/Libp2pChannel.java similarity index 52% rename from src/main/java/io/xdag/libp2p/Libp2pChannel.java rename to src/main/java/io/xdag/net/libp2p/Libp2pChannel.java index 618bbd41..ebfa1859 100755 --- a/src/main/java/io/xdag/libp2p/Libp2pChannel.java +++ b/src/main/java/io/xdag/net/libp2p/Libp2pChannel.java @@ -21,69 +21,117 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.libp2p; +package io.xdag.net.libp2p; import io.libp2p.core.Connection; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.xdag.Bootstrap; +import io.xdag.Kernel; import io.xdag.core.BlockWrapper; -import io.xdag.libp2p.RPCHandler.RPCHandler; +import io.xdag.net.Channel; +import io.xdag.net.handler.Xdag; +import io.xdag.net.libp2p.RPCHandler.RPCHandler; +import io.xdag.net.message.MessageQueue; import io.xdag.net.node.Node; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; +import java.net.InetSocketAddress; + +/** + * @author wawa + */ @Slf4j -public class Libp2pChannel { +public class Libp2pChannel extends Channel { + protected NioSocketChannel socket; + protected boolean isActive; + protected boolean isDisconnected = false; private final Connection connection; - private boolean isActive; - private boolean isDisconnected = false; - private Node node; private final RPCHandler handler; - + protected MessageQueue messageQueue; + public int port; + public String ip; + protected Kernel kernel; public Libp2pChannel(Connection connection, RPCHandler handler) { this.connection = connection; this.handler = handler; } - - //存放连接的节点地址 - public void init(){ - log.debug( "init libp2pChannel"); - String[] ipcompont= connection.remoteAddress().toString().split("/"); - node = new Node(ipcompont[2],Integer.parseInt(ipcompont[4])); -// this.messageQueue = new MessageQueueLib(this); + public void init(Kernel kernel) { + String[] ipString = connection.remoteAddress().toString().split("/"); + ip = ipString[2]; + port = Integer.parseInt(ipString[4]); + inetSocketAddress = new InetSocketAddress(ip,port); + node = new Node(connection.secureSession().getRemoteId().getBytes(),ip,port); + this.messageQueue = new MessageQueue(this); + log.debug("Initwith Node host:" + ip + " port:" + port + " node:" + node.getHexId()); + this.kernel = kernel; } + @Override public void sendNewBlock(BlockWrapper blockWrapper) { - log.debug("send a block hash is {}", Hex.toHexString(blockWrapper.getBlock().getHashLow())); - log.debug("ttl:" + blockWrapper.getTtl()); - handler.getController().sendNewBlock(blockWrapper.getBlock(), blockWrapper.getTtl()); - } - //获取对方的ip - public String getIp(){ - return connection.remoteAddress().toString(); + handler.controller.sendNewBlock(blockWrapper.getBlock(), blockWrapper.getTtl()); } + @Override public void onDisconnect() { isDisconnected = true; } + @Override + public int getPort() { + return 0; + } + + @Override public boolean isDisconnected() { return isDisconnected; } - public Node getNode(){ - return node; + @Override + public MessageQueue getmessageQueue() { + return messageQueue; + } + + @Override + public Kernel getKernel() { + return kernel; } + public RPCHandler getHandler(){ return handler; } + @Override + public InetSocketAddress getInetSocketAddress() { + return inetSocketAddress; + } + + @Override public void setActive(boolean b) { isActive = b; } + @Override public boolean isActive() { return isActive; } + @Override + public Node getNode() { + return node; + } + + @Override + public String getIp() { + return node.getHexId(); + } + + @Override public void dropConnection() { + connection.close(); + } + + @Override + public Xdag getXdag() { + return handler.controller; } } diff --git a/src/main/java/io/xdag/libp2p/Libp2pNetwork.java b/src/main/java/io/xdag/net/libp2p/Libp2pNetwork.java similarity index 70% rename from src/main/java/io/xdag/libp2p/Libp2pNetwork.java rename to src/main/java/io/xdag/net/libp2p/Libp2pNetwork.java index a54e76df..7bdc0010 100755 --- a/src/main/java/io/xdag/libp2p/Libp2pNetwork.java +++ b/src/main/java/io/xdag/net/libp2p/Libp2pNetwork.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.libp2p; +package io.xdag.net.libp2p; import io.libp2p.core.Host; import io.libp2p.core.PeerId; @@ -30,20 +30,19 @@ 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.mux.mplex.MplexStreamMuxer; import io.libp2p.security.noise.NoiseXXSecureChannel; import io.libp2p.transport.tcp.TcpTransport; import io.netty.handler.logging.LogLevel; import io.xdag.Kernel; -import io.xdag.libp2p.RPCHandler.Firewall; -import io.xdag.libp2p.RPCHandler.RPCHandler; -import io.xdag.libp2p.manager.PeerManager; -import io.xdag.libp2p.peer.LibP2PNodeId; -import io.xdag.libp2p.peer.NodeId; -import io.xdag.libp2p.peer.Peer; -import io.xdag.libp2p.peer.PeerAddress; +import io.xdag.net.libp2p.RPCHandler.Firewall; +import io.xdag.net.libp2p.RPCHandler.NonHandler; +import io.xdag.net.libp2p.RPCHandler.RPCHandler; +import io.xdag.net.libp2p.manager.PeerManager; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import io.xdag.net.libp2p.peer.NodeId; import io.xdag.utils.IpUtil; -import io.xdag.utils.MultiaddrPeerAddress; import io.xdag.utils.MultiaddrUtil; import io.xdag.utils.SafeFuture; import lombok.extern.slf4j.Slf4j; @@ -52,27 +51,28 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.time.Duration; -import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Stream; - -//import io.libp2p.core.mux.StreamMuxerProtocol; @Slf4j -public class Libp2pNetwork implements P2PNetwork { - private final RPCHandler rpcHandler; - private final int port; - private final Host host; - private final PrivKey privKeyBytes; - private final NodeId nodeId; - private final InetAddress privateAddress; - private final PeerManager peerManager; +public class Libp2pNetwork implements P2PNetwork { + private ProtocolBinding rpcHandler; + private int port; + private Host host; + private final PrivKey privKey; + private NodeId nodeId; + private InetAddress privateAddress; + protected PeerManager peerManager = new PeerManager(); private final AtomicReference state = new AtomicReference<>(State.IDLE); private final Multiaddr advertisedAddr; + public Libp2pNetwork(PrivKey privKey, Multiaddr listenAddr) { + rpcHandler = new NonHandler(peerManager); + this.privKey = privKey; + this.advertisedAddr = listenAddr; + } public Libp2pNetwork(Kernel kernel){ port = kernel.getConfig().getNodeSpec().getLibp2pPort(); - rpcHandler = new RPCHandler(kernel); + rpcHandler = new RPCHandler(kernel,peerManager); privateAddress = IpUtil.getLocalAddress(); peerManager = new PeerManager(); //种子节点 Privkey从配置文件读取 非种子节点随机生成一个 @@ -80,20 +80,22 @@ public Libp2pNetwork(Kernel kernel){ if(kernel.getConfig().getNodeSpec().isBootnode()){ String Privkey = kernel.getConfig().getNodeSpec().getLibp2pPrivkey(); Bytes privkeybytes = Bytes.fromHexString(Privkey); - this.privKeyBytes = KeyKt.unmarshalPrivateKey(privkeybytes.toArrayUnsafe()); + this.privKey = KeyKt.unmarshalPrivateKey(privkeybytes.toArrayUnsafe()); }else{ - this.privKeyBytes = kernel.getPrivKey(); + this.privKey = kernel.getPrivKey(); } -// PeerId peerId = PeerId.fromHex(Hex.toHexString(privKeyBytes.publicKey().bytes())); - PeerId peerId = PeerId.fromPubKey(privKeyBytes.publicKey()); + PeerId peerId = PeerId.fromPubKey(privKey.publicKey()); this.nodeId = new LibP2PNodeId(peerId); this.advertisedAddr = MultiaddrUtil.fromInetSocketAddress( new InetSocketAddress(kernel.getConfig().getNodeSpec().getNodeIp(), port),nodeId); + } + + private void crate(){ host = BuilderJKt.hostJ(Builder.Defaults.None, b->{ - b.getIdentity().setFactory(()-> privKeyBytes); + b.getIdentity().setFactory(()-> privKey); b.getTransports().add(TcpTransport::new); b.getSecureChannels().add(NoiseXXSecureChannel::new); // b.getMuxers().add(StreamMuxerProtocol.getMplex()); @@ -106,7 +108,6 @@ public Libp2pNetwork(Kernel kernel){ b.getDebug().getMuxFramesHandler().setLogger(LogLevel.DEBUG, "wire.mux"); b.getConnectionHandlers().add(peerManager); }); - } @Override @@ -114,7 +115,9 @@ public SafeFuture start() { if (!state.compareAndSet(State.IDLE, State.RUNNING)) { return SafeFuture.failedFuture(new IllegalStateException("Network already started")); } - log.info("id ={}", host.getPeerId());//16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj + crate(); + //16Uiu2HAm3NZUwzzNHfnnB8ADfnuP5MTDuqjRb3nTRBxPTQ4g7Wjj + log.info("id ={}", host.getPeerId()); log.info("Starting libp2p network..."); return SafeFuture.of(host.start()) .thenApply( @@ -131,40 +134,6 @@ public void dail(String peer) { rpcHandler.dial(host,address); } - @Override - public PeerAddress createPeerAddress(final String peerAddress) { - return MultiaddrPeerAddress.fromAddress(peerAddress); - } - - @Override - public boolean isConnected(final PeerAddress peerAddress) { - return peerManager.getPeer(peerAddress.getId()).isPresent(); - } - - @Override - public Bytes getPrivateKey() { - return Bytes.wrap(privKeyBytes.raw()); - } - - @Override - public Optional getPeer(final NodeId id) { - return peerManager.getPeer(id); - } - - @Override - public Stream streamPeers() { - return peerManager.streamPeers(); - } - - @Override - public NodeId parseNodeId(final String nodeId) { - return new LibP2PNodeId(PeerId.fromBase58(nodeId)); - } - - @Override - public int getPeerCount() { - return peerManager.getPeerCount(); - } @Override public String getNodeAddress() { diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytes32Backed.java b/src/main/java/io/xdag/net/libp2p/P2PNetwork.java similarity index 77% rename from src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytes32Backed.java rename to src/main/java/io/xdag/net/libp2p/P2PNetwork.java index 975989f8..e227dbc2 100644 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytes32Backed.java +++ b/src/main/java/io/xdag/net/libp2p/P2PNetwork.java @@ -21,17 +21,27 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.utils.discoveryutils.bytes; +package io.xdag.net.libp2p; -public class AbstractBytes32Backed implements Bytes32Backed { - protected final Bytes32 bytes; +import io.xdag.net.libp2p.peer.NodeId; +import io.xdag.utils.SafeFuture; - protected AbstractBytes32Backed(final Bytes32 bytes) { - this.bytes = bytes; - } +public interface P2PNetwork

{ + + void dail(String peer); - @Override - public Bytes32 getBytes() { - return bytes; + enum State { + IDLE, + RUNNING, + STOPPED } + + String getNodeAddress(); + + NodeId getNodeId(); + + SafeFuture start(); + + SafeFuture stop(); } + diff --git a/src/main/java/io/xdag/libp2p/RPCHandler/Firewall.java b/src/main/java/io/xdag/net/libp2p/RPCHandler/Firewall.java similarity index 98% rename from src/main/java/io/xdag/libp2p/RPCHandler/Firewall.java rename to src/main/java/io/xdag/net/libp2p/RPCHandler/Firewall.java index bf666252..a43adb74 100644 --- a/src/main/java/io/xdag/libp2p/RPCHandler/Firewall.java +++ b/src/main/java/io/xdag/net/libp2p/RPCHandler/Firewall.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.libp2p.RPCHandler; +package io.xdag.net.libp2p.RPCHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; diff --git a/src/test/java/io/xdag/libp2p/HandlerTest.java b/src/main/java/io/xdag/net/libp2p/RPCHandler/NonHandler.java similarity index 79% rename from src/test/java/io/xdag/libp2p/HandlerTest.java rename to src/main/java/io/xdag/net/libp2p/RPCHandler/NonHandler.java index 6d179d33..b00b06ef 100644 --- a/src/test/java/io/xdag/libp2p/HandlerTest.java +++ b/src/main/java/io/xdag/net/libp2p/RPCHandler/NonHandler.java @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.libp2p; + +package io.xdag.net.libp2p.RPCHandler; import io.libp2p.core.Connection; import io.libp2p.core.P2PChannel; @@ -30,30 +31,21 @@ import io.libp2p.core.multistream.ProtocolDescriptor; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.util.CharsetUtil; -import io.xdag.libp2p.peer.LibP2PNodeId; -import io.xdag.libp2p.peer.NodeId; -import lombok.extern.slf4j.Slf4j; +import io.xdag.net.libp2p.manager.PeerManager; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import io.xdag.net.libp2p.peer.NodeId; + import org.jetbrains.annotations.NotNull; import java.util.concurrent.CompletableFuture; -@Slf4j -@ChannelHandler.Sharable -public class HandlerTest implements ProtocolBinding { - - private String announce; - private Controller controller; - final CompletableFuture activeFuture = new CompletableFuture<>(); - public HandlerTest(String announce, Controller controller) { - this.announce = announce; - this.controller = controller; - } - - public HandlerTest() { +public class NonHandler implements ProtocolBinding { + PeerManager peerManager; + public NonHandler(PeerManager peerManager) { + this.peerManager = peerManager; } @NotNull @@ -66,9 +58,7 @@ public ProtocolDescriptor getProtocolDescriptor() { public CompletableFuture initChannel(@NotNull P2PChannel p2PChannel, @NotNull String s) { final Connection connection = ((Stream) p2PChannel).getConnection(); final NodeId nodeId = new LibP2PNodeId(connection.secureSession().getRemoteId()); - if(!p2PChannel.isInitiator()){ - log.info("p2PChannel.isInitiator() is not ready"); - } + peerManager.handleConnection(connection); Controller controller = new Controller(nodeId, p2PChannel); p2PChannel.pushHandler(controller); return controller.activeFuture; @@ -76,8 +66,9 @@ public CompletableFuture initChannel(@NotNull P2PChannel p2PChannel, - //Xdag03 - //SimpleChannelInboundHandler<> 括号是接受的对象 + /** + * SimpleChannelInboundHandler<> 括号是接受的对象 + */ static class Controller extends SimpleChannelInboundHandler { final NodeId nodeid; @@ -102,10 +93,9 @@ public void channelActive(ChannelHandlerContext ctx) { //ByteBuf 是接受的对象 @Override - protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf buf) throws Exception { + 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/RPCHandler/RPCHandler.java b/src/main/java/io/xdag/net/libp2p/RPCHandler/RPCHandler.java new file mode 100644 index 00000000..b4c5b53b --- /dev/null +++ b/src/main/java/io/xdag/net/libp2p/RPCHandler/RPCHandler.java @@ -0,0 +1,108 @@ +/* + * 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.RPCHandler; + +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.libp2p.Libp2pChannel; +import io.xdag.net.libp2p.manager.PeerManager; +import io.xdag.net.manager.XdagChannelManager; +import io.xdag.net.message.AbstractMessage; +import io.xdag.net.message.impl.Xdag03MessageFactory; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +@Slf4j +public class RPCHandler implements ProtocolBinding { + public Controller controller; + Kernel kernel; + Libp2pChannel libp2pChannel; + XdagBlockHandler blockHandler; + XdagChannelManager channelManager; + PeerManager peerManager; + public RPCHandler(Kernel kernel, PeerManager peerManager) { + this.kernel = kernel; + this.peerManager = peerManager; + this.channelManager = kernel.getChannelMgr(); + } + + @NotNull + @Override + public ProtocolDescriptor getProtocolDescriptor() { + return new ProtocolDescriptor("xdagj"); + } + + @NotNull + @Override + public CompletableFuture initChannel(@NotNull P2PChannel p2PChannel, @NotNull String s) { + final Connection connection = ((io.libp2p.core.Stream) p2PChannel).getConnection(); + peerManager.handleConnection(connection); + libp2pChannel = new Libp2pChannel(connection,this); + libp2pChannel.init(kernel); + channelManager.add(libp2pChannel); + blockHandler = new XdagBlockHandler(libp2pChannel); + blockHandler.setMessageFactory(new Xdag03MessageFactory()); + channelManager.onChannelActive(libp2pChannel,libp2pChannel.getNode()); + MessageCodes messageCodes = new MessageCodes(); + controller = new Controller(kernel,libp2pChannel); + + // add handler + p2PChannel.pushHandler(blockHandler); + p2PChannel.pushHandler(messageCodes); + p2PChannel.pushHandler(controller); + return controller.activeFuture; + } + public static class Controller extends Xdag03 { + + public CompletableFuture activeFuture = new CompletableFuture<>(); + public XdagChannelManager channelManager; + public Controller(Kernel kernel, Channel channel) { + super(kernel, channel); + channelManager = kernel.getChannelMgr(); + msgQueue = channel.getmessageQueue(); + } + @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); + } + } + +} diff --git a/src/main/java/io/xdag/libp2p/manager/PeerManager.java b/src/main/java/io/xdag/net/libp2p/manager/PeerManager.java similarity index 95% rename from src/main/java/io/xdag/libp2p/manager/PeerManager.java rename to src/main/java/io/xdag/net/libp2p/manager/PeerManager.java index 12ed4214..2f2925e3 100755 --- a/src/main/java/io/xdag/libp2p/manager/PeerManager.java +++ b/src/main/java/io/xdag/net/libp2p/manager/PeerManager.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.libp2p.manager; +package io.xdag.net.libp2p.manager; import io.libp2p.core.*; import io.libp2p.core.multiformats.Multiaddr; -import io.xdag.libp2p.RPCHandler.RPCHandler; -import io.xdag.libp2p.peer.LibP2PNodeId; -import io.xdag.libp2p.peer.NodeId; -import io.xdag.libp2p.peer.Peer; +import io.xdag.net.libp2p.RPCHandler.RPCHandler; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import io.xdag.net.libp2p.peer.NodeId; +import io.xdag.net.libp2p.peer.Peer; import io.xdag.utils.MultiaddrPeerAddress; import io.xdag.utils.SafeFuture; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/io/xdag/net/libp2p/peer/DiscoveryPeerConverter.java b/src/main/java/io/xdag/net/libp2p/peer/DiscoveryPeerConverter.java new file mode 100644 index 00000000..6f6d49a6 --- /dev/null +++ b/src/main/java/io/xdag/net/libp2p/peer/DiscoveryPeerConverter.java @@ -0,0 +1,47 @@ +package io.xdag.net.libp2p.peer; + +import io.libp2p.core.PeerId; +import io.libp2p.core.crypto.PubKey; +import io.libp2p.core.multiformats.Multiaddr; +import io.xdag.net.discovery.DiscoveryPeer; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import static io.libp2p.crypto.keys.Secp256k1Kt.unmarshalSecp256k1PublicKey; +import static io.xdag.utils.MultiaddrUtil.addPeerId; + +/** + * @author wawa + */ +public class DiscoveryPeerConverter { + + public static String discoveryPeerToDailId(DiscoveryPeer peer){ + String dailId = fromInetSocketAddress(peer.getNodeAddress(), DiscoveryPeerConverter.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)); + } + 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); + } + private static String protocol(final InetAddress address) { + return address instanceof Inet6Address ? "ip6" : "ip4"; + } +} diff --git a/src/main/java/io/xdag/libp2p/peer/LibP2PNodeId.java b/src/main/java/io/xdag/net/libp2p/peer/LibP2PNodeId.java similarity index 97% rename from src/main/java/io/xdag/libp2p/peer/LibP2PNodeId.java rename to src/main/java/io/xdag/net/libp2p/peer/LibP2PNodeId.java index e5482bac..2773bd69 100644 --- a/src/main/java/io/xdag/libp2p/peer/LibP2PNodeId.java +++ b/src/main/java/io/xdag/net/libp2p/peer/LibP2PNodeId.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.libp2p.peer; +package io.xdag.net.libp2p.peer; import io.libp2p.core.PeerId; import org.apache.tuweni.bytes.Bytes; diff --git a/src/main/java/io/xdag/libp2p/peer/Libp2pNode.java b/src/main/java/io/xdag/net/libp2p/peer/Libp2pNode.java similarity index 97% rename from src/main/java/io/xdag/libp2p/peer/Libp2pNode.java rename to src/main/java/io/xdag/net/libp2p/peer/Libp2pNode.java index 1b33cbd1..840b9be1 100644 --- a/src/main/java/io/xdag/libp2p/peer/Libp2pNode.java +++ b/src/main/java/io/xdag/net/libp2p/peer/Libp2pNode.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.libp2p.peer; +package io.xdag.net.libp2p.peer; import io.libp2p.core.PeerId; import io.xdag.net.node.NodeStat; diff --git a/src/main/java/io/xdag/libp2p/peer/NodeId.java b/src/main/java/io/xdag/net/libp2p/peer/NodeId.java similarity index 98% rename from src/main/java/io/xdag/libp2p/peer/NodeId.java rename to src/main/java/io/xdag/net/libp2p/peer/NodeId.java index 02061714..e0f567db 100644 --- a/src/main/java/io/xdag/libp2p/peer/NodeId.java +++ b/src/main/java/io/xdag/net/libp2p/peer/NodeId.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.libp2p.peer; +package io.xdag.net.libp2p.peer; import org.apache.tuweni.bytes.Bytes; diff --git a/src/main/java/io/xdag/libp2p/peer/Peer.java b/src/main/java/io/xdag/net/libp2p/peer/Peer.java similarity index 95% rename from src/main/java/io/xdag/libp2p/peer/Peer.java rename to src/main/java/io/xdag/net/libp2p/peer/Peer.java index 6159d03b..20db0221 100644 --- a/src/main/java/io/xdag/libp2p/peer/Peer.java +++ b/src/main/java/io/xdag/net/libp2p/peer/Peer.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.libp2p.peer; +package io.xdag.net.libp2p.peer; public interface Peer { @@ -31,6 +31,4 @@ default NodeId getId() { PeerAddress getAddress(); - boolean isConnected(); - } diff --git a/src/main/java/io/xdag/libp2p/peer/PeerAddress.java b/src/main/java/io/xdag/net/libp2p/peer/PeerAddress.java similarity index 98% rename from src/main/java/io/xdag/libp2p/peer/PeerAddress.java rename to src/main/java/io/xdag/net/libp2p/peer/PeerAddress.java index f34b2ece..9f993983 100644 --- a/src/main/java/io/xdag/libp2p/peer/PeerAddress.java +++ b/src/main/java/io/xdag/net/libp2p/peer/PeerAddress.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.libp2p.peer; +package io.xdag.net.libp2p.peer; import java.util.Objects; import java.util.Optional; diff --git a/src/main/java/io/xdag/net/manager/XdagChannelManager.java b/src/main/java/io/xdag/net/manager/XdagChannelManager.java index af9803e8..66de455f 100644 --- a/src/main/java/io/xdag/net/manager/XdagChannelManager.java +++ b/src/main/java/io/xdag/net/manager/XdagChannelManager.java @@ -25,6 +25,7 @@ import io.xdag.Kernel; import io.xdag.core.BlockWrapper; +import io.xdag.net.Channel; import io.xdag.net.XdagChannel; import io.xdag.net.node.Node; import java.net.InetSocketAddress; @@ -36,8 +37,8 @@ @Slf4j public class XdagChannelManager { - protected ConcurrentHashMap channels = new ConcurrentHashMap<>(); - protected ConcurrentHashMap activeChannels = new ConcurrentHashMap<>(); + protected ConcurrentHashMap channels = new ConcurrentHashMap<>(); + protected ConcurrentHashMap activeChannels = new ConcurrentHashMap<>(); private final Kernel kernel; /** Queue with new blocks from other peers */ private final BlockingQueue newForeignBlocks = new LinkedBlockingQueue<>(); @@ -57,13 +58,13 @@ public void start() { blockDistributeThread.start(); } - public void add(XdagChannel ch) { + public void add(Channel ch) { log.debug( "xdag channel manager->Channel added: remoteAddress = {}:{}", ch.getIp(), ch.getPort()); channels.put(ch.getInetSocketAddress(), ch); } - public void notifyDisconnect(XdagChannel channel) { + public void notifyDisconnect(Channel channel) { log.debug("xdag channel manager-> node {}: notifies about disconnect", channel); remove(channel); channel.onDisconnect(); @@ -71,14 +72,14 @@ public void notifyDisconnect(XdagChannel channel) { public Set getActiveAddresses() { Set set = new HashSet<>(); - for (XdagChannel c : activeChannels.values()) { + for (Channel c : activeChannels.values()) { Node p = c.getNode(); set.add(new InetSocketAddress(p.getHost(), p.getPort())); } return set; } - public List getActiveChannels() { + public List getActiveChannels() { return new ArrayList<>(activeChannels.values()); } @@ -110,10 +111,10 @@ public void sendNewBlock(BlockWrapper blockWrapper) { || blockWrapper.getRemoteNode().equals(kernel.getClient().getNode())) { receive = kernel.getClient().getNode(); } else { - XdagChannel receiveChannel = activeChannels.get(blockWrapper.getRemoteNode().getHexId()); + Channel receiveChannel = activeChannels.get(blockWrapper.getRemoteNode().getHexId()); receive = receiveChannel != null ? receiveChannel.getNode() : null; } - for (XdagChannel channel : activeChannels.values()) { + for (Channel channel : activeChannels.values()) { if (receive != null && channel.getNode().getHexId().equals(receive.getHexId())) { log.debug("不发送给他"); continue; @@ -123,7 +124,7 @@ public void sendNewBlock(BlockWrapper blockWrapper) { } } - public void onChannelActive(XdagChannel channel, Node node) { + public void onChannelActive(Channel channel, Node node) { channel.setActive(true); activeChannels.put(node.getHexId(), channel); log.debug("activeChannel size:" + activeChannels.size()); @@ -141,7 +142,7 @@ public int size() { return channels.size(); } - public void remove(XdagChannel ch) { + public void remove(Channel ch) { // log.debug("Channel removed: remoteAddress = {}:{}", ch.getIp(), ch.getPort()); channels.remove(ch.getInetSocketAddress()); if (ch.isActive()) { @@ -186,7 +187,7 @@ public void stop() { blockDistributeThread.interrupt(); } // 关闭所有连接 - for (XdagChannel channel : activeChannels.values()) { + for (Channel channel : activeChannels.values()) { channel.dropConnection(); } } diff --git a/src/main/java/io/xdag/net/message/MessageQueue.java b/src/main/java/io/xdag/net/message/MessageQueue.java index a71c89ab..28e8b0c1 100644 --- a/src/main/java/io/xdag/net/message/MessageQueue.java +++ b/src/main/java/io/xdag/net/message/MessageQueue.java @@ -25,7 +25,7 @@ import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; -import io.xdag.net.XdagChannel; +import io.xdag.net.Channel; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ScheduledExecutorService; @@ -53,9 +53,9 @@ public class MessageQueue { private final Queue respondQueue = new ConcurrentLinkedQueue<>(); private ChannelHandlerContext ctx = null; private ScheduledFuture timerTask; - private final XdagChannel channel; + private final Channel channel; - public MessageQueue(XdagChannel channel) { + public MessageQueue(Channel channel) { this.channel = channel; } diff --git a/src/main/java/io/xdag/nat/NatConfiguration.java b/src/main/java/io/xdag/net/nat/NatConfiguration.java similarity index 98% rename from src/main/java/io/xdag/nat/NatConfiguration.java rename to src/main/java/io/xdag/net/nat/NatConfiguration.java index 7ba95e85..a0317464 100644 --- a/src/main/java/io/xdag/nat/NatConfiguration.java +++ b/src/main/java/io/xdag/net/nat/NatConfiguration.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.nat; +package io.xdag.net.nat; public class NatConfiguration { private final NatMethod natMethod; diff --git a/src/main/java/io/xdag/nat/NatManager.java b/src/main/java/io/xdag/net/nat/NatManager.java similarity index 99% rename from src/main/java/io/xdag/nat/NatManager.java rename to src/main/java/io/xdag/net/nat/NatManager.java index a8deb38f..bedafa3b 100644 --- a/src/main/java/io/xdag/nat/NatManager.java +++ b/src/main/java/io/xdag/net/nat/NatManager.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.nat; +package io.xdag.net.nat; import com.google.common.annotations.VisibleForTesting; import io.xdag.utils.SafeFuture; diff --git a/src/main/java/io/xdag/nat/NatMethod.java b/src/main/java/io/xdag/net/nat/NatMethod.java similarity index 97% rename from src/main/java/io/xdag/nat/NatMethod.java rename to src/main/java/io/xdag/net/nat/NatMethod.java index 32a32921..2ccb987e 100644 --- a/src/main/java/io/xdag/nat/NatMethod.java +++ b/src/main/java/io/xdag/net/nat/NatMethod.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.nat; +package io.xdag.net.nat; public enum NatMethod { UPNP, diff --git a/src/main/java/io/xdag/nat/NatPortMapping.java b/src/main/java/io/xdag/net/nat/NatPortMapping.java similarity index 98% rename from src/main/java/io/xdag/nat/NatPortMapping.java rename to src/main/java/io/xdag/net/nat/NatPortMapping.java index 08ce9ee4..fa67837e 100644 --- a/src/main/java/io/xdag/nat/NatPortMapping.java +++ b/src/main/java/io/xdag/net/nat/NatPortMapping.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.nat; +package io.xdag.net.nat; public class NatPortMapping { diff --git a/src/main/java/io/xdag/nat/NatService.java b/src/main/java/io/xdag/net/nat/NatService.java similarity index 97% rename from src/main/java/io/xdag/nat/NatService.java rename to src/main/java/io/xdag/net/nat/NatService.java index b3d57623..272f2db2 100644 --- a/src/main/java/io/xdag/nat/NatService.java +++ b/src/main/java/io/xdag/net/nat/NatService.java @@ -21,13 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import io.xdag.utils.Service; import lombok.extern.slf4j.Slf4j; - import java.util.Optional; @Slf4j @@ -60,7 +59,7 @@ public NatService( } @Override - protected SafeFuture doStart() { + public SafeFuture doStart() { if (maybeNatManager.isEmpty()) { return SafeFuture.COMPLETE; } diff --git a/src/main/java/io/xdag/nat/NatServiceType.java b/src/main/java/io/xdag/net/nat/NatServiceType.java similarity index 98% rename from src/main/java/io/xdag/nat/NatServiceType.java rename to src/main/java/io/xdag/net/nat/NatServiceType.java index a02b547f..2601f907 100644 --- a/src/main/java/io/xdag/nat/NatServiceType.java +++ b/src/main/java/io/xdag/net/nat/NatServiceType.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.nat; +package io.xdag.net.nat; public enum NatServiceType { XDAG_DISCOVERY("xdag_discovery"), diff --git a/src/main/java/io/xdag/nat/NetworkProtocol.java b/src/main/java/io/xdag/net/nat/NetworkProtocol.java similarity index 97% rename from src/main/java/io/xdag/nat/NetworkProtocol.java rename to src/main/java/io/xdag/net/nat/NetworkProtocol.java index a3a8091b..a55448bb 100644 --- a/src/main/java/io/xdag/nat/NetworkProtocol.java +++ b/src/main/java/io/xdag/net/nat/NetworkProtocol.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.nat; +package io.xdag.net.nat; public enum NetworkProtocol { UDP, diff --git a/src/main/java/io/xdag/nat/OkHttpStreamClient.java b/src/main/java/io/xdag/net/nat/OkHttpStreamClient.java similarity index 99% rename from src/main/java/io/xdag/nat/OkHttpStreamClient.java rename to src/main/java/io/xdag/net/nat/OkHttpStreamClient.java index 467c8ad1..a6f2369b 100644 --- a/src/main/java/io/xdag/nat/OkHttpStreamClient.java +++ b/src/main/java/io/xdag/net/nat/OkHttpStreamClient.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.nat; +package io.xdag.net.nat; import okhttp3.*; import org.jupnp.model.message.*; diff --git a/src/main/java/io/xdag/nat/UpnpClient.java b/src/main/java/io/xdag/net/nat/UpnpClient.java similarity index 99% rename from src/main/java/io/xdag/nat/UpnpClient.java rename to src/main/java/io/xdag/net/nat/UpnpClient.java index 7c97c340..5f9d2146 100644 --- a/src/main/java/io/xdag/nat/UpnpClient.java +++ b/src/main/java/io/xdag/net/nat/UpnpClient.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.nat; +package io.xdag.net.nat; import com.google.common.annotations.VisibleForTesting; import io.xdag.utils.SafeFuture; @@ -36,7 +36,6 @@ import org.jupnp.registry.RegistryListener; import org.jupnp.support.model.PortMapping; - import java.util.Optional; import static io.xdag.utils.FutureUtil.ignoreFuture; @@ -120,7 +119,7 @@ public SafeFuture requestPortForward( } @VisibleForTesting - SafeFuture getWanIpFuture() { + public SafeFuture getWanIpFuture() { return wanIpFuture; } diff --git a/src/main/java/io/xdag/nat/XdagGetExternalIP.java b/src/main/java/io/xdag/net/nat/XdagGetExternalIP.java similarity index 99% rename from src/main/java/io/xdag/nat/XdagGetExternalIP.java rename to src/main/java/io/xdag/net/nat/XdagGetExternalIP.java index 62e6d0c6..db240629 100644 --- a/src/main/java/io/xdag/nat/XdagGetExternalIP.java +++ b/src/main/java/io/xdag/net/nat/XdagGetExternalIP.java @@ -21,11 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import lombok.extern.slf4j.Slf4j; - import org.jupnp.model.action.ActionInvocation; import org.jupnp.model.message.UpnpResponse; import org.jupnp.model.meta.RemoteDevice; @@ -34,9 +33,6 @@ import org.jupnp.model.meta.Service; import org.jupnp.support.igd.callback.GetExternalIP; - - - import java.util.Optional; @Slf4j diff --git a/src/main/java/io/xdag/nat/XdagNatServiceConfiguration.java b/src/main/java/io/xdag/net/nat/XdagNatServiceConfiguration.java similarity index 99% rename from src/main/java/io/xdag/nat/XdagNatServiceConfiguration.java rename to src/main/java/io/xdag/net/nat/XdagNatServiceConfiguration.java index e6256e80..dbed6d9e 100644 --- a/src/main/java/io/xdag/nat/XdagNatServiceConfiguration.java +++ b/src/main/java/io/xdag/net/nat/XdagNatServiceConfiguration.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.nat; +package io.xdag.net.nat; import lombok.extern.slf4j.Slf4j; import org.jupnp.DefaultUpnpServiceConfiguration; diff --git a/src/main/java/io/xdag/nat/XdagPortMappingAdd.java b/src/main/java/io/xdag/net/nat/XdagPortMappingAdd.java similarity index 99% rename from src/main/java/io/xdag/nat/XdagPortMappingAdd.java rename to src/main/java/io/xdag/net/nat/XdagPortMappingAdd.java index 0af51cbf..1080e672 100644 --- a/src/main/java/io/xdag/nat/XdagPortMappingAdd.java +++ b/src/main/java/io/xdag/net/nat/XdagPortMappingAdd.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.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/io/xdag/nat/XdagPortMappingDelete.java b/src/main/java/io/xdag/net/nat/XdagPortMappingDelete.java similarity index 99% rename from src/main/java/io/xdag/nat/XdagPortMappingDelete.java rename to src/main/java/io/xdag/net/nat/XdagPortMappingDelete.java index 285b6669..4adc7fd9 100644 --- a/src/main/java/io/xdag/nat/XdagPortMappingDelete.java +++ b/src/main/java/io/xdag/net/nat/XdagPortMappingDelete.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.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/io/xdag/nat/XdagRegistryListener.java b/src/main/java/io/xdag/net/nat/XdagRegistryListener.java similarity index 99% rename from src/main/java/io/xdag/nat/XdagRegistryListener.java rename to src/main/java/io/xdag/net/nat/XdagRegistryListener.java index fae4b65d..d88c2c84 100644 --- a/src/main/java/io/xdag/nat/XdagRegistryListener.java +++ b/src/main/java/io/xdag/net/nat/XdagRegistryListener.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.nat; +package io.xdag.net.nat; import org.jupnp.model.meta.LocalDevice; import org.jupnp.model.meta.RemoteDevice; diff --git a/src/main/java/io/xdag/net/node/NodeManager.java b/src/main/java/io/xdag/net/node/NodeManager.java index f2fe7b91..e0dd7724 100644 --- a/src/main/java/io/xdag/net/node/NodeManager.java +++ b/src/main/java/io/xdag/net/node/NodeManager.java @@ -32,32 +32,29 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Stream; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; -import io.libp2p.core.PeerId; import io.xdag.Kernel; import io.xdag.config.Config; -import io.xdag.discovery.DiscoveryController; -import io.xdag.discovery.peers.DiscoveryPeer; -import io.xdag.discovery.peers.PeerTable; -import io.xdag.libp2p.Libp2pChannel; -import io.xdag.libp2p.Libp2pNetwork; +import io.xdag.net.Channel; +import io.xdag.net.discovery.DiscoveryController; +import io.xdag.net.discovery.DiscoveryPeer; +import io.xdag.net.libp2p.Libp2pNetwork; -import io.xdag.libp2p.manager.ChannelManager; -import io.xdag.libp2p.peer.LibP2PNodeId; -import io.xdag.net.XdagChannel; import io.xdag.net.XdagClient; import io.xdag.net.handler.XdagChannelInitializer; import io.xdag.net.manager.NetDBManager; import io.xdag.net.manager.XdagChannelManager; import io.xdag.net.message.NetDB; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.util.encoders.Hex; + +import static io.xdag.net.libp2p.peer.DiscoveryPeerConverter.discoveryPeerToDailId; + @Slf4j public class NodeManager { @@ -86,11 +83,11 @@ public Thread newThread(@Nonnull Runnable r) { private volatile boolean isRunning; private ScheduledFuture connectFuture; private ScheduledFuture fetchFuture; - private ScheduledFuture connectlibp2pFuture; - private final Set hadConnectnode = new HashSet<>(); - private final ChannelManager channelManager; + private ScheduledFuture connectlibp2PFuture; private final DiscoveryController discoveryController; + private Set hadConnected; Libp2pNetwork libp2pNetwork; + private Node myself; public NodeManager(Kernel kernel) { this.kernel = kernel; @@ -101,8 +98,8 @@ public NodeManager(Kernel kernel) { this.config = kernel.getConfig(); this.netDBManager = kernel.getNetDBMgr(); this.discoveryController = kernel.getDiscoveryController(); - this.channelManager = kernel.getChannelManager(); libp2pNetwork = kernel.getLibp2pNetwork(); + myself = new Node(kernel.getConfig().getNodeSpec().getNodeIp(),kernel.getConfig().getNodeSpec().getLibp2pPort()); } /** start the node manager */ @@ -116,7 +113,8 @@ 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,1,5,TimeUnit.SECONDS); + connectlibp2PFuture = exec.scheduleAtFixedRate(this::doConnectlibp2p, 10, 10, TimeUnit.SECONDS); + hadConnected = new HashSet<>(); isRunning = true; log.debug("Node manager started"); } @@ -126,6 +124,7 @@ public synchronized void stop() { if (isRunning) { connectFuture.cancel(true); fetchFuture.cancel(false); + connectlibp2PFuture.cancel(true); isRunning = false; exec.shutdown(); log.debug("Node manager stop..."); @@ -179,7 +178,6 @@ public Set getSeedNodes(NetDB netDB) { return null; } } - //todo:明天测试 逻辑思路 public void doConnect() { Set activeAddress = channelMgr.getActiveAddresses(); @@ -209,27 +207,17 @@ public void doConnect(String ip, int port) { client.connect(ip, port, initializer); } } - //todo :加一个不能重复连接的逻辑 + //todo:发现之后的节点只能自动连接一次 public void doConnectlibp2p(){ - List libp2pChannels = kernel.getChannelManager().getactiveChannel(); - Stream nodes = libp2pChannels.stream().map(Libp2pChannel::getNode); - PeerTable peerTable = kernel.getDiscoveryController().getPeerTable(); - Collection discoveryPeers = peerTable.getAllPeers(); - List discoveryPeers1 = new ArrayList<>(discoveryPeers); - for (DiscoveryPeer d : discoveryPeers1) { - if ((d.getEndpoint().getHost().equals(kernel.getDiscoveryController().getMynode().getHost()) - && (d.getEndpoint().getTcpPort().equals(kernel.getDiscoveryController().getMynode().getTcpPort()))) - || hadConnectnode.contains(d) || - nodes.anyMatch(a -> a.equals(new Node(d.getEndpoint().getHost(), d.getEndpoint().getTcpPort().getAsInt())))) { - continue; + Set activeAddress = channelMgr.getActiveAddresses(); + List discoveryPeerList = + discoveryController.getDiscV5Service().streamKnownPeers().collect(Collectors.toList()); + for (DiscoveryPeer p :discoveryPeerList){ + Node node = new Node(p.nodeAddress().getHostName(),p.nodeAddress().getPort()); + if(!myself.equals(node)&&!activeAddress.contains(p.getNodeAddress())&&!hadConnected.contains(node)){ + kernel.getLibp2pNetwork().dail(discoveryPeerToDailId(p)); + hadConnected.add(node); } - StringBuilder stringBuilder = new StringBuilder(); -// 连接格式 ("/ip4/192.168.3.5/tcp/11112/ipfs/16Uiu2HAmRfT8vNbCbvjQGsfqWUtmZvrj5y8XZXiyUz6HVSqZW8gy") - String id = new LibP2PNodeId(PeerId.fromHex(Hex.toHexString(d.getId().extractArray()))).toString(); - stringBuilder.append("/ip4/").append(d.getEndpoint().getHost()).append("/tcp/").append(d.getEndpoint().getTcpPort().getAsInt()). - append("/ipfs/").append(id); - kernel.getLibp2pNetwork().dail(stringBuilder.toString()); - hadConnectnode.add(d); } } @@ -239,22 +227,13 @@ public Set getNewNode() { public Map getActiveNode() { Map nodes = new HashMap<>(); - List activeAddress = channelMgr.getActiveChannels(); - for (XdagChannel address : activeAddress) { - Node node = address.getNode(); - Long time = lastConnect.getIfPresent(node); - nodes.put(node, time); - } - return nodes; - } - public Map getActiveNode0() { - Map nodes = new HashMap<>(); - List activeAddress = channelManager.getactiveChannel(); - for (Libp2pChannel address : activeAddress) { + List activeAddress = channelMgr.getActiveChannels(); + for (Channel address : activeAddress) { Node node = address.getNode(); Long time = lastConnect.getIfPresent(node); nodes.put(node, time); } return nodes; } + } diff --git a/src/main/java/io/xdag/rpc/Web3.java b/src/main/java/io/xdag/rpc/Web3.java index 78e91e37..720cb750 100644 --- a/src/main/java/io/xdag/rpc/Web3.java +++ b/src/main/java/io/xdag/rpc/Web3.java @@ -1,3 +1,26 @@ +/* + * 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.rpc; import io.xdag.rpc.modules.web3.Web3XdagModule; diff --git a/src/main/java/io/xdag/rpc/Web3Impl.java b/src/main/java/io/xdag/rpc/Web3Impl.java index 471da0b3..948af3d6 100644 --- a/src/main/java/io/xdag/rpc/Web3Impl.java +++ b/src/main/java/io/xdag/rpc/Web3Impl.java @@ -1,6 +1,30 @@ +/* + * 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.rpc; import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.dto.StatusDTO; import io.xdag.rpc.modules.web3.Web3XdagModule; import io.xdag.rpc.modules.xdag.XdagModule; @@ -148,4 +172,9 @@ public BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws public BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception { return web3XdagModule.xdag_getBlockByHash(blockHash,full); } + + @Override + public StatusDTO xdag_getStatus() throws Exception { + return web3XdagModule.xdag_getStatus(); + } } diff --git a/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java b/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java index 465b914b..74e84018 100644 --- a/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java +++ b/src/main/java/io/xdag/rpc/cors/CorsConfiguration.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.cors; import org.slf4j.Logger; diff --git a/src/main/java/io/xdag/rpc/cors/OriginValidator.java b/src/main/java/io/xdag/rpc/cors/OriginValidator.java index 71e9d32b..bfbe6819 100644 --- a/src/main/java/io/xdag/rpc/cors/OriginValidator.java +++ b/src/main/java/io/xdag/rpc/cors/OriginValidator.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.cors; import org.slf4j.Logger; diff --git a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java index 56c4cd9c..4025266d 100644 --- a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java +++ b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.dto; @@ -9,9 +32,9 @@ public class BlockResultDTO { // blockInfo // rawData - String height; String data; + public BlockResultDTO(long height) { this.height = Long.toHexString(height); this.data = "hello"; diff --git a/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java index 1edb3b04..e3391d19 100644 --- a/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java +++ b/src/main/java/io/xdag/rpc/dto/ETHBlockResultDTO.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.dto; import lombok.Data; diff --git a/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java b/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java index 4da87bf4..3850b754 100644 --- a/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java +++ b/src/main/java/io/xdag/rpc/dto/ETHTransactionReceiptDTO.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.dto; import io.xdag.core.Block; diff --git a/src/main/java/io/xdag/rpc/dto/StatusDTO.java b/src/main/java/io/xdag/rpc/dto/StatusDTO.java index 97b09ce2..ecd89462 100644 --- a/src/main/java/io/xdag/rpc/dto/StatusDTO.java +++ b/src/main/java/io/xdag/rpc/dto/StatusDTO.java @@ -1,10 +1,48 @@ +/* + * 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.rpc.dto; +import lombok.Data; + +import java.math.BigInteger; + +import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; + +@Data public class StatusDTO { // status 状态信息 - // host - // nblocks - // nmain - // diff + private final String nblocks; + private final String nmain; + private final String diff; + private final String supply; + + public StatusDTO(long nblocks, long nmain, BigInteger diff, double supply) { + this.nblocks = toQuantityJsonHex(nblocks); + this.nmain = toQuantityJsonHex(nmain); + this.diff = toQuantityJsonHex(diff); + this.supply = toQuantityJsonHex(supply); + } + } diff --git a/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java index 378b0af3..356cb0da 100644 --- a/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java +++ b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java @@ -1,92 +1,29 @@ -//package io.xdag.rpc.dto; -// -//import io.xdag.core.Block; -// -//import static io.xdag.rpc.utils.TypeConverter.toUnformattedJsonHex; -// -//public class TransactionReceiptDTO { -// private String transactionHash; // hash of the transaction. -// private String transactionIndex; // integer of the transactions index position in the block. -// private String blockHash; // hash of the block where this transaction was in. -// private String blockNumber; // block number where this transaction was in. -// private String cumulativeGasUsed; // The total amount of gas used when this transaction was executed in the block. -// private String gasUsed; // The amount of gas used by this specific transaction alone. -// private String contractAddress; // The contract address created, if the transaction was a contract creation, otherwise null . -// private String from; // address of the sender. -// private String to; // address of the receiver. null when it's a contract creation transaction. -// private String status; // either 1 (success) or 0 (failure) -// private String logsBloom; // Bloom filter for light clients to quickly retrieve related logs. -// -// public TransactionReceiptDTO(Block block) { -// TransactionReceipt receipt = txInfo.getReceipt(); -// -// status = toQuantityJsonHex(txInfo.getReceipt().getStatus()); -// blockHash = toUnformattedJsonHex(block.getHash()); -// blockNumber = toQuantityJsonHex(block.getNumber()); -// -// RskAddress contractAddress = receipt.getTransaction().getContractAddress(); -// if (contractAddress != null) { -// this.contractAddress = contractAddress.toJsonString(); -// } -// -// cumulativeGasUsed = toQuantityJsonHex(receipt.getCumulativeGas()); -// from = receipt.getTransaction().getSender().toJsonString(); -// gasUsed = toQuantityJsonHex(receipt.getGasUsed()); -// -// logs = new LogFilterElement[receipt.getLogInfoList().size()]; -// for (int i = 0; i < logs.length; i++) { -// LogInfo logInfo = receipt.getLogInfoList().get(i); -// logs[i] = new LogFilterElement(logInfo, block, txInfo.getIndex(), -// txInfo.getReceipt().getTransaction(), i); -// } -// -// to = receipt.getTransaction().getReceiveAddress().toJsonString(); -// transactionHash = receipt.getTransaction().getHash().toJsonString(); -// transactionIndex = toQuantityJsonHex(txInfo.getIndex()); -// logsBloom = toUnformattedJsonHex(txInfo.getReceipt().getBloomFilter().getData()); -// } -// -// public String getTransactionHash() { -// return transactionHash; -// } -// -// public String getTransactionIndex() { -// return transactionIndex; -// } -// -// public String getBlockHash() { -// return blockHash; -// } -// -// public String getBlockNumber() { -// return blockNumber; -// } -// -// public String getCumulativeGasUsed() { -// return cumulativeGasUsed; -// } -// -// public String getGasUsed() { -// return gasUsed; -// } -// -// public String getContractAddress() { -// return contractAddress; -// } -// -// public String getFrom() { -// return from; -// } -// -// public String getTo() { -// return to; -// } -// -// public String getStatus() { -// return status; -// } -// -// public String getLogsBloom() { -// return logsBloom; -// } -//} +/* + * 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.rpc.dto; + +public class TransactionReceiptDTO { + + +} diff --git a/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java b/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java index 6838cecb..38e45238 100644 --- a/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java +++ b/src/main/java/io/xdag/rpc/exception/XdagErrorResolver.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.exception; import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java b/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java index a2c574e8..b2285465 100644 --- a/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java +++ b/src/main/java/io/xdag/rpc/exception/XdagJsonRpcRequestException.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.exception; public class XdagJsonRpcRequestException extends RuntimeException { diff --git a/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java b/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java index 0f5d2065..e0ab8942 100644 --- a/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java +++ b/src/main/java/io/xdag/rpc/filter/JsonRpcMethodFilter.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.filter; import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java index 141f4c48..37071c13 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcBooleanResult.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonValue; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java index 57cd72b1..d775cfd9 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcError.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import java.util.Objects; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java index 6f545da2..08eb395a 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcErrorResponse.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import java.util.Objects; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java index 7eeb9250..53983147 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcIdentifiableMessage.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java index c6e5a878..6ba72828 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcInternalError.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; public class JsonRpcInternalError extends JsonRpcError { diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java index c177fd09..f7011374 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcMessage.java @@ -1,4 +1,27 @@ -package io.xdag.rpc.jsonrpc; + +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java index d5b89b4c..b6f06fa7 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcRequest.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java index edba8184..6a8de426 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResult.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; public abstract class JsonRpcResult implements JsonRpcResultOrError{ diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java index f2a84e1a..14a3868e 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultOrError.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java index 45a17842..7ec69fa1 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcResultResponse.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import java.util.Objects; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java index 39c50a47..a0bc6bc6 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonRpcVersion.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java b/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java index 013b418d..19569cb1 100644 --- a/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java +++ b/src/main/java/io/xdag/rpc/jsonrpc/JsonUtils.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.jsonrpc; import org.bouncycastle.util.encoders.Hex; diff --git a/src/main/java/io/xdag/rpc/modules/ModuleDescription.java b/src/main/java/io/xdag/rpc/modules/ModuleDescription.java index 088a4e73..28d5e8a2 100644 --- a/src/main/java/io/xdag/rpc/modules/ModuleDescription.java +++ b/src/main/java/io/xdag/rpc/modules/ModuleDescription.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules; import java.util.ArrayList; diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java index 78348961..360ed88c 100644 --- a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcMethod.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java index 2691db11..d50d9a02 100644 --- a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequest.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules; import com.fasterxml.jackson.annotation.JsonSubTypes; diff --git a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java index 4ae8ea0d..7625f746 100644 --- a/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java +++ b/src/main/java/io/xdag/rpc/modules/XdagJsonRpcRequestVisitor.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules; diff --git a/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java b/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java index 2cfdb074..3c702330 100644 --- a/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java +++ b/src/main/java/io/xdag/rpc/modules/debug/DebugModule.java @@ -1,21 +1,26 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.modules.debug; import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java b/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java index 5e3cbce2..44c8a718 100644 --- a/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/debug/DebugModuleImpl.java @@ -1,21 +1,26 @@ ///* -// * This file is part of RskJ -// * Copyright (C) 2018 RSK Labs Ltd. +// * The MIT License (MIT) // * -// * This program is free software: you can redistribute it and/or modify -// * it under the terms of the GNU Lesser General Public License as published by -// * the Free Software Foundation, either version 3 of the License, or -// * (at your option) any later version. +// * Copyright (c) 2020-2030 The XdagJ Developers // * -// * This program is distributed in the hope that it will be useful, -// * but WITHOUT ANY WARRANTY; without even the implied warranty of -// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// * GNU Lesser General Public License for more details. +// * 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: // * -// * You should have received a copy of the GNU Lesser General Public License -// * along with this program. If not, see . +// * 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.rpc.modules.debug; // //import com.fasterxml.jackson.databind.JsonNode; diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModule.java b/src/main/java/io/xdag/rpc/modules/eth/EthModule.java index 98f66fbc..33c1acaa 100644 --- a/src/main/java/io/xdag/rpc/modules/eth/EthModule.java +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModule.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.eth; import io.xdag.rpc.Web3; diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java b/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java index 8675c4ac..74e1d4c7 100644 --- a/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModuleTransaction.java @@ -1,21 +1,26 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.modules.eth; diff --git a/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java b/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java index 9bfad1e3..b82b00cc 100644 --- a/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java +++ b/src/main/java/io/xdag/rpc/modules/eth/EthModuleWallet.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.eth; public interface EthModuleWallet { diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java index 55a7276b..67b46195 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModule.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.web3; import io.xdag.rpc.dto.ETHBlockResultDTO; diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java index 147b8af7..0d15fe3b 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3EthModuleImpl.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.web3; import io.xdag.rpc.dto.ETHBlockResultDTO; diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java index 9cce248e..a6ca15d9 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModule.java @@ -1,7 +1,31 @@ +/* + * 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.rpc.modules.web3; import io.xdag.rpc.Web3; import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.dto.StatusDTO; import io.xdag.rpc.modules.xdag.XdagModule; @@ -50,4 +74,5 @@ default String xdag_sendTransaction(Web3.CallArguments args) { BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception; + StatusDTO xdag_getStatus() throws Exception; } diff --git a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java index dd95af96..1838b60f 100644 --- a/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java +++ b/src/main/java/io/xdag/rpc/modules/web3/Web3XdagModuleImpl.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.web3; import com.sun.jdi.LongValue; @@ -7,7 +30,9 @@ import io.xdag.core.Block; import io.xdag.core.Blockchain; import io.xdag.core.XdagState; +import io.xdag.core.XdagStats; import io.xdag.rpc.dto.BlockResultDTO; +import io.xdag.rpc.dto.StatusDTO; import io.xdag.rpc.modules.xdag.XdagModule; import io.xdag.utils.StringUtils; import org.bouncycastle.util.encoders.Hex; @@ -129,4 +154,14 @@ public BlockResultDTO xdag_getBlockByNumber(String bnOrId, Boolean full) throws public BlockResultDTO xdag_getBlockByHash(String blockHash, Boolean full) throws Exception { return null; } + + @Override + public StatusDTO xdag_getStatus() throws Exception { + XdagStats xdagStats = kernel.getBlockchain().getXdagStats(); + long nblocks = Math.max(xdagStats.getTotalnblocks(),xdagStats.getNblocks()); + long nmain = Math.max(xdagStats.getTotalnblocks(),xdagStats.getNmain()); + BigInteger diff = xdagStats.getDifficulty(); + double supply = amount2xdag(kernel.getBlockchain().getSupply(Math.max(xdagStats.nmain,xdagStats.totalnmain))); + return new StatusDTO(nblocks,nmain,diff,supply); + } } diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java index fcb63739..c8d73fd8 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModule.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.rpc.Web3; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java index e66dcb8d..c46a852d 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChain.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.rpc.dto.BlockResultDTO; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java index fc0734bb..8abe6d4e 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleChainBase.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.rpc.dto.BlockResultDTO; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java index 74134dd5..4032a9e1 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransaction.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.rpc.Web3; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java index 55a6ea30..a5d0a8ba 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.core.Block; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java index c22195bc..3ad4798e 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionDisabled.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.core.Blockchain; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java index 614e2d14..3c4b9480 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionEnabled.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import io.xdag.core.Blockchain; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java index 10db63a1..6956ed64 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWallet.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; public interface XdagModuleWallet { diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java index 51328a86..2fc39007 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleWalletDisabled.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.modules.xdag; import org.slf4j.Logger; diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java deleted file mode 100644 index 672168b9..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/SubscriptionId.java +++ /dev/null @@ -1,52 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//import com.fasterxml.jackson.annotation.JsonCreator; -//import com.fasterxml.jackson.annotation.JsonValue; -//import io.xdag.rpc.jsonrpc.JsonRpcResult; -//import io.xdag.rpc.utils.TypeConverter; -// -//import java.security.SecureRandom; -//import java.util.Arrays; -// -//public class SubscriptionId extends JsonRpcResult { -// private final byte[] id; -// -// @JsonCreator -// public SubscriptionId(String hexId) { -// this.id = TypeConverter.stringHexToByteArray(hexId); -// } -// -// public SubscriptionId() { -// this.id = new byte[16]; -// new SecureRandom().nextBytes(id); -// } -// -// public byte[] getId() { -// return Arrays.copyOf(id, id.length); -// } -// -// @Override -// public int hashCode() { -// return Arrays.hashCode(id); -// } -// -// @Override -// public boolean equals(Object o) { -// if (o == this) { -// return true; -// } -// -// if (!(o instanceof SubscriptionId)) { -// return false; -// } -// -// SubscriptionId other = (SubscriptionId) o; -// return Arrays.equals(this.id, other.id); -// } -// -// @JsonValue -// @SuppressWarnings("unused") -// private String serialize() { -// return TypeConverter.toJsonHex(id); -// } -//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java deleted file mode 100644 index b3125962..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGSubscribeRequest.java +++ /dev/null @@ -1,47 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//import com.fasterxml.jackson.annotation.JsonCreator; -//import com.fasterxml.jackson.annotation.JsonInclude; -//import com.fasterxml.jackson.annotation.JsonProperty; -//import io.netty.channel.ChannelHandlerContext; -//import io.xdag.rpc.jsonrpc.JsonRpcResultOrError; -//import io.xdag.rpc.jsonrpc.JsonRpcVersion; -//import io.xdag.rpc.modules.XdagJsonRpcMethod; -//import io.xdag.rpc.modules.XdagJsonRpcRequest; -//import io.xdag.rpc.modules.XdagJsonRpcRequestVisitor; -// -//import java.util.Objects; -// -//public class XDAGSubscribeRequest extends XdagJsonRpcRequest { -// -// private final XdagSubscribeParams params; -// -// @JsonCreator -// public XDAGSubscribeRequest( -// @JsonProperty("jsonrpc") JsonRpcVersion version, -// @JsonProperty("method") XdagJsonRpcMethod method, -// @JsonProperty("id") Integer id, -// @JsonProperty("params") XdagSubscribeParams params) { -// super(version, verifyMethod(method), Objects.requireNonNull(id)); -// this.params = Objects.requireNonNull(params); -// } -// -// @JsonInclude(JsonInclude.Include.NON_NULL) -// public XdagSubscribeParams getParams() { -// return params; -// } -// -// @Override -// public JsonRpcResultOrError accept(XdagJsonRpcRequestVisitor visitor, ChannelHandlerContext ctx) { -// return visitor.visit(this, ctx); -// } -// -// private static XdagJsonRpcMethod verifyMethod(XdagJsonRpcMethod method) { -// if (method != XdagJsonRpcMethod.ETH_SUBSCRIBE) { -// throw new IllegalArgumentException( -// "Wrong method mapped to eth_subscribe. Check JSON mapping configuration in JsonRpcRequest." -// ); -// } -// return method; -// } -//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java deleted file mode 100644 index e1d285b6..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XDAGUnsubscribeRequest.java +++ /dev/null @@ -1,4 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//public class XDAGUnsubscribeRequest { -//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java deleted file mode 100644 index 124b8377..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParams.java +++ /dev/null @@ -1,15 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//import com.fasterxml.jackson.annotation.JsonTypeInfo; -//import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -//import io.netty.channel.Channel; -// -// -//@JsonDeserialize(using = XdagSubscribeParamsDeserializer.class) -//@JsonTypeInfo(use = JsonTypeInfo.Id.NONE) -//public interface XdagSubscribeParams { -// SubscriptionId accept(XdagSubscribeParamsVisitor visitor, Channel channel); -//} -// -// -// diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java deleted file mode 100644 index 52945d35..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsDeserializer.java +++ /dev/null @@ -1,60 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//import com.fasterxml.jackson.core.JsonParser; -//import com.fasterxml.jackson.core.JsonToken; -//import com.fasterxml.jackson.databind.DeserializationContext; -//import com.fasterxml.jackson.databind.JsonDeserializer; -// -//import java.io.IOException; -//import java.util.HashMap; -// -//public class XdagSubscribeParamsDeserializer extends JsonDeserializer { -// -// private final HashMap> subscriptionTypes; -// -// public XdagSubscribeParamsDeserializer() { -// this.subscriptionTypes = new HashMap<>(); -//// this.subscriptionTypes.put("newHeads", EthSubscribeNewHeadsParams.class); -//// this.subscriptionTypes.put("logs", EthSubscribeLogsParams.class); -// } -// -// @Override -// public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { -// if (!p.isExpectedStartArrayToken()) { -// return ctxt.handleUnexpectedToken( -// XdagSubscribeParams.class, -// p.currentToken(), -// p, -// "xdag_subscribe parameters are expected to be arrays" -// ); -// } -// p.nextToken(); // skip '[' -// String subscriptionType = p.getText(); -// Class subscriptionTypeClass = subscriptionTypes.get(subscriptionType); -// p.nextToken(); -// XdagSubscribeParams params; -// if (p.isExpectedStartObjectToken()) { -// params = p.readValueAs(subscriptionTypeClass); -// p.nextToken(); -// } else { -// try { -// params = subscriptionTypeClass.newInstance(); -// } catch (InstantiationException | IllegalAccessException e) { -// return ctxt.handleInstantiationProblem( -// subscriptionTypeClass, -// null, -// e -// ); -// } -// } -// if (p.currentToken() != JsonToken.END_ARRAY) { -// return ctxt.handleUnexpectedToken( -// XdagSubscribeParams.class, -// p.currentToken(), -// p, -// "eth_subscribe can only have one object to configure subscription" -// ); -// } -// return params; -// } -//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java deleted file mode 100644 index a05f33cb..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscribeParamsVisitor.java +++ /dev/null @@ -1,19 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//import io.netty.channel.Channel; -// -//public interface XdagSubscribeParamsVisitor { -//// /** -//// * @param params new heads subscription request parameters. -//// * @param channel a Netty channel to subscribe notifications to. -//// * @return a subscription id which should be used as an unsubscribe parameter. -//// */ -//// SubscriptionId visit(XdagSubscribeNewHeadsParams params, Channel channel); -//// -//// /** -//// * @param params logs subscription request parameters. -//// * @param channel a Netty channel to subscribe notifications to. -//// * @return a subscription id which should be used as an unsubscribe parameter. -//// */ -//// SubscriptionId visit(XdagSubscribeLogsParams params, Channel channel); -//} diff --git a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java b/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java deleted file mode 100644 index 3dc72b22..00000000 --- a/src/main/java/io/xdag/rpc/modules/xdag/subscribe/XdagSubscriptionNotificationDTO.java +++ /dev/null @@ -1,4 +0,0 @@ -//package io.xdag.rpc.modules.xdag.subscribe; -// -//public interface XdagSubscriptionNotificationDTO { -//} diff --git a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java index 0b3f07f5..f7024759 100644 --- a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java +++ b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3FilterHandler.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.netty; import io.netty.channel.ChannelFutureListener; diff --git a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java index fc1e2d68..d9e98d86 100644 --- a/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java +++ b/src/main/java/io/xdag/rpc/netty/JsonRpcWeb3ServerHandler.java @@ -1,21 +1,26 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java b/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java index b42b0862..f89adf18 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java +++ b/src/main/java/io/xdag/rpc/netty/Web3HttpMethodFilterHandler.java @@ -1,19 +1,25 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; diff --git a/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java b/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java index bdb93600..7a63257d 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java +++ b/src/main/java/io/xdag/rpc/netty/Web3HttpServer.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.netty; import io.netty.bootstrap.ServerBootstrap; diff --git a/src/main/java/io/xdag/rpc/netty/Web3Result.java b/src/main/java/io/xdag/rpc/netty/Web3Result.java index c658174d..85857597 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3Result.java +++ b/src/main/java/io/xdag/rpc/netty/Web3Result.java @@ -1,19 +1,25 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; diff --git a/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java b/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java index 565ced14..769e4ef5 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java +++ b/src/main/java/io/xdag/rpc/netty/Web3ResultHttpResponseHandler.java @@ -1,19 +1,25 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; diff --git a/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java b/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java index 75a5943d..90f69363 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java +++ b/src/main/java/io/xdag/rpc/netty/Web3ResultWebSocketResponseHandler.java @@ -1,19 +1,25 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; diff --git a/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java index 7a90b54e..bfccf498 100644 --- a/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java +++ b/src/main/java/io/xdag/rpc/netty/Web3WebSocketServer.java @@ -1,19 +1,25 @@ /* - * This file is part of RskJ - * Copyright (C) 2018 RSK Labs Ltd. + * The MIT License (MIT) * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Copyright (c) 2020-2030 The XdagJ Developers * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * 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: * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see . + * 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.rpc.netty; diff --git a/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java index a904bfb9..c8c8f012 100644 --- a/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java +++ b/src/main/java/io/xdag/rpc/netty/XdagJsonRpcHandler.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.netty; import io.netty.buffer.ByteBufHolder; diff --git a/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java b/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java index 5a352929..c0f52a9e 100644 --- a/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java +++ b/src/main/java/io/xdag/rpc/serialize/JacksonBasedRpcSerializer.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.serialize; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java b/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java index 322d902b..bc469e48 100644 --- a/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java +++ b/src/main/java/io/xdag/rpc/serialize/JsonRpcSerializer.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.serialize; import com.fasterxml.jackson.core.JsonProcessingException; diff --git a/src/main/java/io/xdag/rpc/utils/HttpUtils.java b/src/main/java/io/xdag/rpc/utils/HttpUtils.java index ba424275..777a831e 100644 --- a/src/main/java/io/xdag/rpc/utils/HttpUtils.java +++ b/src/main/java/io/xdag/rpc/utils/HttpUtils.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.utils; public class HttpUtils { diff --git a/src/main/java/io/xdag/rpc/utils/TypeConverter.java b/src/main/java/io/xdag/rpc/utils/TypeConverter.java index ab4b21ec..c8ce8f9b 100644 --- a/src/main/java/io/xdag/rpc/utils/TypeConverter.java +++ b/src/main/java/io/xdag/rpc/utils/TypeConverter.java @@ -1,3 +1,26 @@ +/* + * 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.rpc.utils; import org.bouncycastle.util.encoders.Hex; diff --git a/src/main/java/io/xdag/utils/BasicUtils.java b/src/main/java/io/xdag/utils/BasicUtils.java index cf17758c..5b98d247 100644 --- a/src/main/java/io/xdag/utils/BasicUtils.java +++ b/src/main/java/io/xdag/utils/BasicUtils.java @@ -31,6 +31,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.text.NumberFormat; import java.util.regex.Pattern; import java.util.zip.CRC32; @@ -140,18 +141,16 @@ public static String formatDouble(double d) { } /** - * Xfer: transferred 4479658898 10.430000000 XDAG to the address - * 0000002f28322e9d817fd94a1357e51a. 10.43 Xfer: transferred 42949672960 - * 10.000000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 10 Xfer: - * transferred 4398046511104 1024.000000000 XDAG to the address - * 0000002f28322e9d817fd94a1357e51a. 1024 + * Xfer:transferred 44796588980 10.430000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 10.43 + * Xfer:transferred 42949672960 10.000000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 10 + * Xfer:transferred 4398046511104 1024.000000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 1024 */ public static double amount2xdag(long xdag) { long first = xdag >> 32; long temp = xdag - (first << 32); double tem = temp / Math.pow(2, 32); BigDecimal bigDecimal = new BigDecimal(first + tem); - return bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); + return bigDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue(); } public static boolean crc32Verify(byte[] src, int crc) { diff --git a/src/main/java/io/xdag/utils/BytesUtils.java b/src/main/java/io/xdag/utils/BytesUtils.java index 7856867b..ab4520b0 100644 --- a/src/main/java/io/xdag/utils/BytesUtils.java +++ b/src/main/java/io/xdag/utils/BytesUtils.java @@ -23,9 +23,9 @@ */ package io.xdag.utils; +import com.google.common.io.BaseEncoding; import io.xdag.crypto.jni.Native; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -98,7 +98,7 @@ public static short bytesToShort(byte[] input, int offset, boolean littleEndian) } public static String toHexString(byte[] data) { - return data == null ? "" : Hex.toHexString(data); + return data == null ? "" : BaseEncoding.base16().lowerCase().encode(data); } public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) { diff --git a/src/main/java/io/xdag/utils/MultiaddrPeerAddress.java b/src/main/java/io/xdag/utils/MultiaddrPeerAddress.java index 11b383e6..b26f5e31 100644 --- a/src/main/java/io/xdag/utils/MultiaddrPeerAddress.java +++ b/src/main/java/io/xdag/utils/MultiaddrPeerAddress.java @@ -27,9 +27,9 @@ import io.libp2p.core.PeerId; import io.libp2p.core.multiformats.Multiaddr; import io.libp2p.core.multiformats.Protocol; -import io.xdag.libp2p.peer.LibP2PNodeId; -import io.xdag.libp2p.peer.NodeId; -import io.xdag.libp2p.peer.PeerAddress; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import io.xdag.net.libp2p.peer.NodeId; +import io.xdag.net.libp2p.peer.PeerAddress; import java.util.Objects; diff --git a/src/main/java/io/xdag/utils/MultiaddrUtil.java b/src/main/java/io/xdag/utils/MultiaddrUtil.java index 296ab125..3599787b 100644 --- a/src/main/java/io/xdag/utils/MultiaddrUtil.java +++ b/src/main/java/io/xdag/utils/MultiaddrUtil.java @@ -21,21 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.utils;/* - * Copyright 2020 ConsenSys AG. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on - * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ +package io.xdag.utils; import io.libp2p.core.multiformats.Multiaddr; -import io.xdag.libp2p.peer.NodeId; +import io.xdag.net.libp2p.peer.NodeId; import java.net.Inet6Address; import java.net.InetAddress; @@ -61,7 +50,7 @@ public static Multiaddr fromInetSocketAddress( return addPeerId(fromInetSocketAddress(address, "tcp"), nodeId); } - private static Multiaddr addPeerId(final Multiaddr addr, final NodeId nodeId) { + public static Multiaddr addPeerId(final Multiaddr addr, final NodeId nodeId) { return new Multiaddr(addr, Multiaddr.fromString("/p2p/" + nodeId.toBase58())); } diff --git a/src/main/java/io/xdag/utils/StringUtils.java b/src/main/java/io/xdag/utils/StringUtils.java index a30358ea..d4c6af32 100644 --- a/src/main/java/io/xdag/utils/StringUtils.java +++ b/src/main/java/io/xdag/utils/StringUtils.java @@ -26,13 +26,14 @@ import org.bouncycastle.util.encoders.Hex; import java.math.BigDecimal; +import java.math.RoundingMode; public class StringUtils { public static double getDouble(String value) { double num = Double.parseDouble(value); BigDecimal bigDecimal = new BigDecimal(num); - return bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); + return bigDecimal.setScale(2, RoundingMode.HALF_UP).doubleValue(); } public static byte[] getHash(String address) { @@ -43,11 +44,4 @@ public static byte[] getHash(String address) { return hash; } - public static int getNum(String value) { - int num = 20; - if (value != null) { - num = Integer.parseInt(value); - } - return num; - } } diff --git a/src/main/java/io/xdag/utils/discoveryutils/BouncyCastleMessageDigestFactory.java b/src/main/java/io/xdag/utils/discoveryutils/BouncyCastleMessageDigestFactory.java deleted file mode 100644 index 8b44e49e..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/BouncyCastleMessageDigestFactory.java +++ /dev/null @@ -1,39 +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.utils.discoveryutils; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - - -public class BouncyCastleMessageDigestFactory { - private static final BouncyCastleProvider securityProvider = new BouncyCastleProvider(); - - @SuppressWarnings("DoNotInvokeMessageDigestDirectly") - public static MessageDigest create(final String algorithm) throws NoSuchAlgorithmException { - return MessageDigest.getInstance(algorithm, securityProvider); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/MalformedRLPInputException.java b/src/main/java/io/xdag/utils/discoveryutils/MalformedRLPInputException.java deleted file mode 100644 index 89dfd5fa..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/MalformedRLPInputException.java +++ /dev/null @@ -1,32 +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.utils.discoveryutils; - -import io.xdag.utils.discoveryutils.bytes.uint.RLPException; - -public class MalformedRLPInputException extends RLPException { - public MalformedRLPInputException(final String message) { - super(message); - } -} \ No newline at end of file diff --git a/src/main/java/io/xdag/utils/discoveryutils/NetworkUtility.java b/src/main/java/io/xdag/utils/discoveryutils/NetworkUtility.java deleted file mode 100644 index df5e3f98..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/NetworkUtility.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.utils.discoveryutils; - -import com.google.common.base.Suppliers; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.util.Enumeration; -import java.util.function.Supplier; - -public class NetworkUtility { - - private NetworkUtility() {} - - private static final Supplier ipv6Available = - Suppliers.memoize(NetworkUtility::checkIpv6Availability); - - /** - * The standard for IPv6 availability is if the machine has any IPv6 addresses. - * - * @return Returns true if any IPv6 addresses are iterable via {@link NetworkInterface}. - */ - private static Boolean checkIpv6Availability() { - try { - final Enumeration networkInterfaces = - NetworkInterface.getNetworkInterfaces(); - while (networkInterfaces.hasMoreElements()) { - final Enumeration addresses = - networkInterfaces.nextElement().getInetAddresses(); - while (addresses.hasMoreElements()) { - if (addresses.nextElement() instanceof Inet6Address) { - // Found an IPv6 address, hence the IPv6 stack is available. - return true; - } - } - } - } catch (final Exception ignore) { - // Any exception means we treat it as not available. - } - return false; - } - - /** - * Checks the port is not null and is in the valid range port (1-65536). - * - * @param port The port to check. - * @return True if the port is valid, false otherwise. - */ - public static boolean isValidPort(final int port) { - return port > 0 && port < 65536; - } - -} - diff --git a/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryPacketDecodingException.java b/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryPacketDecodingException.java deleted file mode 100644 index 88a43d61..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryPacketDecodingException.java +++ /dev/null @@ -1,34 +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.utils.discoveryutils; - -public class PeerDiscoveryPacketDecodingException extends RuntimeException { - public PeerDiscoveryPacketDecodingException(final String message) { - super(message); - } - - public PeerDiscoveryPacketDecodingException(final String message, final Throwable cause) { - super(message, cause); - } -} \ No newline at end of file diff --git a/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryStatus.java b/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryStatus.java deleted file mode 100644 index 777e7ada..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/PeerDiscoveryStatus.java +++ /dev/null @@ -1,51 +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.utils.discoveryutils; - -public enum PeerDiscoveryStatus { - - /** - * Represents a newly discovered {@link DiscoveryPeer}, prior to commencing the bonding exchange. - */ - KNOWN, - - /** - * Bonding with this peer is in progress. If we're unable to establish communication and/or - * complete the bonding exchange, the {@link DiscoveryPeer} remains in this state, until we - * ultimately desist. - */ - BONDING, - - /** - * We have successfully bonded with this {@link DiscoveryPeer}, and we are able to exchange - * messages with them. - */ - BONDED; - - @Override - public String toString() { - return name().toLowerCase(); - } -} - diff --git a/src/main/java/io/xdag/utils/discoveryutils/Preconditions.java b/src/main/java/io/xdag/utils/discoveryutils/Preconditions.java deleted file mode 100644 index f900d841..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/Preconditions.java +++ /dev/null @@ -1,40 +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.utils.discoveryutils; - -import java.util.function.Function; - -public class Preconditions { - private Preconditions() {} - - public static void checkGuard( - final boolean condition, - final Function exceptionGenerator, - final String template, - final Object... variables) { - if (!condition) { - throw exceptionGenerator.apply(String.format(template, variables)); - } - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/RLPInput.java b/src/main/java/io/xdag/utils/discoveryutils/RLPInput.java deleted file mode 100644 index 939c9136..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/RLPInput.java +++ /dev/null @@ -1,86 +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.utils.discoveryutils; - - -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import java.math.BigInteger; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -public interface RLPInput { - - boolean isDone(); - - boolean nextIsList(); - - boolean nextIsNull(); - - boolean isEndOfCurrentList(); - - void skipNext(); - - - int enterList(); - - void leaveList(); - - - void leaveList(boolean ignoreRest); - - long readLongScalar(); - - BigInteger readBigIntegerScalar(); - - short readShort(); - - default int readUnsignedShort() { - return readShort() & 0xFFFF; - } - - InetAddress readInetAddress(); - - BytesValue readBytesValue(); - - - BytesValue raw(); - - void reset(); - - default List readList(final Function valueReader) { - final int size = enterList(); - final List res = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - try { - res.add(valueReader.apply(this)); - } catch (final Exception ignored) { - - } - } - leaveList(); - return res; - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/Subscribers.java b/src/main/java/io/xdag/utils/discoveryutils/Subscribers.java deleted file mode 100644 index b6f7056d..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/Subscribers.java +++ /dev/null @@ -1,39 +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.utils.discoveryutils; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; - -public class Subscribers { - - private final Map subscribers = new ConcurrentHashMap<>(); - - public void forEach(final Consumer action) { - subscribers.values().forEach(action); - } - -} - diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytesValue.java deleted file mode 100644 index 096bde62..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractBytesValue.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.utils.discoveryutils.bytes; - -import java.security.MessageDigest; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -public abstract class AbstractBytesValue implements BytesValue { - - private static final char[] hexCode = "0123456789abcdef".toCharArray(); - - @Override - public BytesValue slice(final int index) { - final int size = size(); - if (index >= size) { - return EMPTY; - } - return slice(index, size - index); - } - - @Override - public void copyTo(final MutableBytesValue dest) { - checkArgument( - dest.size() == size(), - "Cannot copy %s bytes to destination of non-equal size %s", - size(), - dest.size()); - - copyTo(dest, 0); - } - - @Override - public void copyTo(final MutableBytesValue destination, final int destinationOffset) { - // Special casing an empty source or the following checks might throw (even though we have - // nothing to copy anyway) and this gets inconvenient for generic methods using copyTo() as - // they may have to special case empty values because of this. As an example, - // concatenate(EMPTY, EMPTY) would need to be special cased without this. - if (size() == 0) return; - - checkElementIndex(destinationOffset, destination.size()); - checkArgument( - destination.size() - destinationOffset >= size(), - "Cannot copy %s bytes, destination has only %s bytes from index %s", - size(), - destination.size() - destinationOffset, - destinationOffset); - - for (int i = 0; i < size(); i++) destination.set(destinationOffset + i, get(i)); - } - - @Override - public BytesValue copy() { - return BytesValue.wrap(extractArray()); - } - - @Override - public int commonPrefixLength(final BytesValue other) { - final int ourSize = size(); - final int otherSize = other.size(); - int i = 0; - while (i < ourSize && i < otherSize && get(i) == other.get(i)) { - i++; - } - return i; - } - - @Override - public BytesValue commonPrefix(final BytesValue other) { - return slice(0, commonPrefixLength(other)); - } - - @Override - public void update(final MessageDigest digest) { - for (int i = 0; i < size(); i++) { - digest.update(get(i)); - } - } - - @Override - public boolean isZero() { - for (int i = 0; i < size(); i++) { - if (get(i) != 0) return false; - } - return true; - } - - @Override - public MutableBytesValue mutableCopy() { - return MutableBytesValue.wrap(extractArray()); - } - - /** - * Compare this value and the provided one for equality. - * - *

Two {@link BytesValue} are equal is they have the same time and contain the exact same bytes - * in order. - * - * @param other The other value to test for equality. - * @return Whether this value and {@code other} are equal. - */ - @Override - public boolean equals(final Object other) { - if (!(other instanceof BytesValue)) return false; - - final BytesValue that = (BytesValue) other; - if (this.size() != that.size()) return false; - - for (int i = 0; i < size(); i++) { - if (this.get(i) != that.get(i)) return false; - } - return true; - } - - @Override - public int hashCode() { - int result = 1; - for (int i = 0; i < size(); i++) result = 31 * result + get(i); - return result; - } - - @Override - public String toString() { - final int size = size(); - final StringBuilder r = new StringBuilder(2 + size * 2); - r.append("0x"); - - for (int i = 0; i < size; i++) { - final byte b = get(i); - r.append(hexCode[b >> 4 & 15]); - r.append(hexCode[b & 15]); - } - - return r.toString(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractRLPOutput.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractRLPOutput.java deleted file mode 100644 index 2b52e3dd..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/AbstractRLPOutput.java +++ /dev/null @@ -1,189 +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.utils.discoveryutils.bytes; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.List; - -import static com.google.common.base.Preconditions.checkState; -import static io.xdag.utils.discoveryutils.bytes.RLPEncodingHelpers.*; - -abstract class AbstractRLPOutput implements RLPOutput { - /* - * The algorithm implemented works as follows: - * - * Values written to the output are accumulated in the 'values' list. When a list is started, it - * is indicated by adding a specific marker in that list (LIST_MARKER). - * While this is gathered, we also incrementally compute the size of the payload of every list of - * that output. Those sizes are stored in 'payloadSizes': when all the output has been added, - * payloadSizes[i] will contain the size of the (encoded) payload of the ith list in 'values' - * (that is, the list that starts at the ith LIST_MARKER in 'values'). - * - * With that information gathered, encoded() can write its output in a single walk of 'values': - * values can encoded directly, and every time we read a list marker, we use the corresponding - * payload size to write the proper prefix and continue. - * - * The main remaining aspect is how the values of 'payloadSizes' are computed. Computing the size - * of a list without nesting inside is easy: simply add the encoded size of any newly added value - * to the running size. The difficulty is with nesting: when we start a new list, we need to - * track both the sizes of the previous list and the new one. To deal with that, we use the small - * stack 'parentListStack': it stores the index in 'payloadSizes' of every currently "open" lists. - * In other words, payloadSises[parentListStack[stackSize - 1]] corresponds to the size of the - * current list, the one to which newly added value are currently written (until the next call - * to 'endList()' that is, while payloadSises[parentListStack[stackSize - 2]] would be the size - * of the parent list, .... - * - * Note that when a new value is added, we add its size only the currently running list. We should - * add that size to that of any parent list as well, but we do so indirectly when a list is - * finished: when 'endList()' is called, we add the size of the full list we just finished (and - * whose size we have now have completely) to its parent size. - * - * Side-note: this class internally and informally use "element" to refer to a non list items. - */ - - private static final BytesValue LIST_MARKER = BytesValue.wrap(new byte[0]); - - private final List values = new ArrayList<>(); - // For every value i in values, rlpEncoded.get(i) will be true only if the value stored is an - // already encoded item. - private final BitSet rlpEncoded = new BitSet(); - - // First element is the total size of everything (the encoding may be a single non-list item, so - // this handle that case more easily; we need that value to size out final output). Following - // elements holds the size of the payload of the ith list in 'values'. - private int[] payloadSizes = new int[8]; - private int listsCount = 1; // number of lists current in 'values' + 1. - - private int[] parentListStack = new int[4]; - private int stackSize = 1; - - private int currentList() { - return parentListStack[stackSize - 1]; - } - - @Override - public void writeBytesValue(final BytesValue v) { - checkState( - stackSize > 1 || values.isEmpty(), "Terminated RLP output, cannot add more elements"); - values.add(v); - payloadSizes[currentList()] += elementSize(v); - } - - @Override - public void startList() { - values.add(LIST_MARKER); - ++listsCount; // we'll add a new element to payloadSizes - ++stackSize; // and to the list stack. - - // Resize our lists if necessary. - if (listsCount > payloadSizes.length) { - payloadSizes = Arrays.copyOf(payloadSizes, (payloadSizes.length * 3) / 2); - } - if (stackSize > parentListStack.length) { - parentListStack = Arrays.copyOf(parentListStack, (parentListStack.length * 3) / 2); - } - - // The new current list size is store in the slot we just made room for by incrementing - // listsCount - parentListStack[stackSize - 1] = listsCount - 1; - } - - @Override - public void endList() { - checkState(stackSize > 1, "LeaveList() called with no prior matching startList()"); - - final int current = currentList(); - final int finishedListSize = listSize(payloadSizes[current]); - --stackSize; - - // We just finished an item of our parent list, add it to that parent list size now. - final int newCurrent = currentList(); - payloadSizes[newCurrent] += finishedListSize; - } - - /** - * Computes the final encoded data size. - * - * @return The size of the RLP-encoded data written to this output. - * @throws IllegalStateException if some opened list haven't been closed (the output is not valid - * as is). - */ - public int encodedSize() { - checkState(stackSize == 1, "A list has been entered (startList()) but not left (endList())"); - return payloadSizes[0]; - } - - /** - * Write the rlp encoded value to the provided {@link MutableBytesValue} - * - * @param mutableBytesValue the value to which the rlp-data will be written - */ - public void writeEncoded(final MutableBytesValue mutableBytesValue) { - // Special case where we encode only a single non-list item (note that listsCount is initially - // set to 1, so listsCount == 1 really mean no list explicitly added to the output). - if (listsCount == 1) { - // writeBytesValue make sure we cannot have more than 1 value without a list - assert values.size() == 1; - final BytesValue value = values.get(0); - - final int finalOffset; - // Single non-list value. - if (rlpEncoded.get(0)) { - value.copyTo(mutableBytesValue, 0); - finalOffset = value.size(); - } else { - finalOffset = writeElement(value, mutableBytesValue, 0); - } - checkState( - finalOffset == mutableBytesValue.size(), - "Expected single element RLP encode to be of size %s but was of size %s.", - mutableBytesValue.size(), - finalOffset); - return; - } - - int offset = 0; - int listIdx = 0; - for (int i = 0; i < values.size(); i++) { - final BytesValue value = values.get(i); - if (value == LIST_MARKER) { - final int payloadSize = payloadSizes[++listIdx]; - offset = writeListHeader(payloadSize, mutableBytesValue, offset); - } else if (rlpEncoded.get(i)) { - value.copyTo(mutableBytesValue, offset); - offset += value.size(); - } else { - offset = writeElement(value, mutableBytesValue, offset); - } - } - - checkState( - offset == mutableBytesValue.size(), - "Expected RLP encoding to be of size %s but was of size %s.", - mutableBytesValue.size(), - offset); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytes32.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytes32.java deleted file mode 100644 index 6c153fef..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytes32.java +++ /dev/null @@ -1,70 +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.utils.discoveryutils.bytes; - -import static com.google.common.base.Preconditions.checkArgument; - -/** An implementation of {@link Bytes32} backed by a byte array ({@code byte[]}). */ -class ArrayWrappingBytes32 extends ArrayWrappingBytesValue implements Bytes32 { - - ArrayWrappingBytes32(final byte[] bytes) { - this(checkLength(bytes), 0); - } - - ArrayWrappingBytes32(final byte[] bytes, final int offset) { - super(checkLength(bytes, offset), offset, SIZE); - } - - // Ensures a proper error message. - private static byte[] checkLength(final byte[] bytes) { - checkArgument(bytes.length == SIZE, "Expected %s bytes but got %s", SIZE, bytes.length); - return bytes; - } - - // Ensures a proper error message. - private static byte[] checkLength(final byte[] bytes, final int offset) { - checkArgument( - bytes.length - offset >= SIZE, - "Expected at least %s bytes from offset %s but got only %s", - SIZE, - offset, - bytes.length - offset); - return bytes; - } - - @Override - public Bytes32 copy() { - // Because MutableArrayWrappingBytesValue overrides this, we know we are immutable. We may - // retain more than necessary however. - if (offset == 0 && length == bytes.length) return this; - - return new ArrayWrappingBytes32(arrayCopy()); - } - - @Override - public MutableBytes32 mutableCopy() { - return new MutableArrayWrappingBytes32(arrayCopy()); - } -} - diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytesValue.java deleted file mode 100644 index f76bf9d1..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/ArrayWrappingBytesValue.java +++ /dev/null @@ -1,190 +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.utils.discoveryutils.bytes; - -import io.vertx.core.buffer.Buffer; - -import java.security.MessageDigest; -import java.util.Arrays; - -import static com.google.common.base.Preconditions.*; - -public class ArrayWrappingBytesValue extends AbstractBytesValue { - - protected final byte[] bytes; - protected final int offset; - protected final int length; - - public ArrayWrappingBytesValue(final byte[] bytes) { - this(bytes, 0, bytes.length); - } - - ArrayWrappingBytesValue(final byte[] bytes, final int offset, final int length) { - checkNotNull(bytes, "Invalid 'null' byte array provided"); - checkArgument(length >= 0, "Invalid negative length provided"); - if (bytes.length > 0) { - checkElementIndex(offset, bytes.length); - } - checkArgument( - offset + length <= bytes.length, - "Provided length %s is too big: the value has only %s bytes from offset %s", - length, - bytes.length - offset, - offset); - - this.bytes = bytes; - this.offset = offset; - this.length = length; - } - - private byte[] extractOrGetArrayUnsafe() { - if (offset == 0 && length == bytes.length) { - return bytes; - } - - return Arrays.copyOfRange(bytes, offset, offset + length); - } - - @Override - public int size() { - return length; - } - - @Override - public byte get(final int i) { - // Check bounds because while the array access would throw, the error message would be confusing - // for the caller. - checkElementIndex(i, size()); - return bytes[offset + i]; - } - - @Override - public BytesValue slice(final int index, final int length) { - if (index == 0 && length == size()) { - return this; - } - if (length == 0) { - return BytesValue.EMPTY; - } - - checkElementIndex(index, size()); - checkArgument( - index + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - index, - index); - - return length == Bytes32.SIZE - ? new ArrayWrappingBytes32(bytes, offset + index) - : new ArrayWrappingBytesValue(bytes, offset + index, length); - } - - byte[] arrayCopy() { - return Arrays.copyOfRange(bytes, offset, offset + length); - } - - @Override - public BytesValue copy() { - // Because MutableArrayWrappingBytesValue overrides this, we know we are immutable. We may - // retain more than necessary however. - if (offset == 0 && length == bytes.length) { - return this; - } - - return new ArrayWrappingBytesValue(arrayCopy()); - } - - @Override - public MutableBytesValue mutableCopy() { - return new MutableArrayWrappingBytesValue(arrayCopy()); - } - - @Override - public int commonPrefixLength(final BytesValue other) { - if (!(other instanceof ArrayWrappingBytesValue)) { - return super.commonPrefixLength(other); - } - final ArrayWrappingBytesValue o = (ArrayWrappingBytesValue) other; - int i = 0; - while (i < length && i < o.length && bytes[offset + i] == o.bytes[o.offset + i]) { - i++; - } - return i; - } - - @Override - public void update(final MessageDigest digest) { - digest.update(bytes, offset, length); - } - - @Override - public void copyTo(final MutableBytesValue dest) { - checkArgument( - dest.size() == size(), - "Cannot copy %s bytes to destination of non-equal size %s", - size(), - dest.size()); - - copyTo(dest, 0); - } - - @Override - public void copyTo(final MutableBytesValue destination, final int destinationOffset) { - if (!(destination instanceof MutableArrayWrappingBytesValue)) { - super.copyTo(destination, destinationOffset); - return; - } - - // Special casing an empty source or the following checks might throw (even though we have - // nothing to copy anyway) and this gets inconvenient for generic methods using copyTo() as - // they may have to special case empty values because of this. As an example, - // concatenate(EMPTY, EMPTY) would need to be special cased without this. - if (size() == 0) { - return; - } - - checkElementIndex(destinationOffset, destination.size()); - checkArgument( - destination.size() - destinationOffset >= size(), - "Cannot copy %s bytes, destination has only %s bytes from index %s", - size(), - destination.size() - destinationOffset, - destinationOffset); - - final MutableArrayWrappingBytesValue d = (MutableArrayWrappingBytesValue) destination; - System.arraycopy(bytes, offset, d.bytes, d.offset + destinationOffset, size()); - } - - @Override - public void appendTo(final Buffer buffer) { - buffer.appendBytes(bytes, offset, length); - } - - @Override - public byte[] getArrayUnsafe() { - return extractOrGetArrayUnsafe(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32.java deleted file mode 100644 index 799d56e5..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32.java +++ /dev/null @@ -1,191 +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.utils.discoveryutils.bytes; - -import io.xdag.utils.discoveryutils.bytes.uint.Int256; -import io.xdag.utils.discoveryutils.bytes.uint.UInt256; -import io.xdag.utils.discoveryutils.bytes.uint.UInt256Bytes; - -import static com.google.common.base.Preconditions.checkArgument; - -public interface Bytes32 extends BytesValue { - int SIZE = 32; - - Bytes32 FALSE = UInt256Bytes.of(0); - Bytes32 TRUE = UInt256Bytes.of(1); - Bytes32 ZERO = wrap(new byte[32]); - - /** - * Wraps the provided byte array, which must be of length 32, as a {@link Bytes32}. - * - *

Note that value is not copied, only wrapped, and thus any future update to {@code value} - * will be reflected in the returned value. - * - * @param bytes The bytes to wrap. - * @return A {@link Bytes32} wrapping {@code value}. - * @throws IllegalArgumentException if {@code value.length != 32}. - */ - static Bytes32 wrap(final byte[] bytes) { - checkArgument(bytes.length == SIZE, "Expected %s bytes but got %s", SIZE, bytes.length); - return wrap(bytes, 0); - } - - /** - * Wraps a slice/sub-part of the provided array as a {@link Bytes32}. - * - *

Note that value is not copied, only wrapped, and thus any future update to {@code value} - * within the wrapped parts will be reflected in the returned value. - * - * @param bytes The bytes to wrap. - * @param offset The index (inclusive) in {@code value} of the first byte exposed by the returned - * value. In other words, you will have {@code wrap(value, i).get(0) == value[i]}. - * @return A {@link Bytes32} that exposes the bytes of {@code value} from {@code offset} - * (inclusive) to {@code offset + 32} (exclusive). - * @throws IndexOutOfBoundsException if {@code offset < 0 || (value.length > 0 && offset >= - * value.length)}. - * @throws IllegalArgumentException if {@code length < 0 || offset + 32 > value.length}. - */ - static Bytes32 wrap(final byte[] bytes, final int offset) { - return new ArrayWrappingBytes32(bytes, offset); - } - - /** - * Wraps a slice/sub-part of the provided value as a {@link Bytes32}. - * - *

Note that value is not copied, only wrapped, and thus any future update to {@code value} - * within the wrapped parts will be reflected in the returned value. - * - * @param bytes The bytes to wrap. - * @param offset The index (inclusive) in {@code value} of the first byte exposed by the returned - * value. In other words, you will have {@code wrap(value, i).get(0) == value.get(i)}. - * @return A {@link Bytes32} that exposes the bytes of {@code value} from {@code offset} - * (inclusive) to {@code offset + 32} (exclusive). - * @throws IndexOutOfBoundsException if {@code offset < 0 || (value.size() > 0 && offset >= - * value.size())}. - * @throws IllegalArgumentException if {@code length < 0 || offset + 32 > value.size()}. - */ - static Bytes32 wrap(final BytesValue bytes, final int offset) { - final BytesValue slice = bytes.slice(offset, Bytes32.SIZE); - return slice instanceof Bytes32 ? (Bytes32) slice : new WrappingBytes32(slice); - } - - /** - * Left pad a {@link BytesValue} with zero bytes to create a {@link Bytes32} - * - * @param value The bytes value pad. - * @return A {@link Bytes32} that exposes the left-padded bytes of {@code value}. - * @throws IllegalArgumentException if {@code value.size() > 32}. - */ - static Bytes32 leftPad(final BytesValue value) { - checkArgument( - value.size() <= SIZE, "Expected at most %s bytes but got only %s", SIZE, value.size()); - - final MutableBytes32 bytes = MutableBytes32.create(); - value.copyTo(bytes, SIZE - value.size()); - return bytes; - } - - /** - * Parse an hexadecimal string into a {@link Bytes32}. - * - *

This method is lenient in that {@code str} may of an odd length, in which case it will - * behave exactly as if it had an additional 0 in front. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". That - * representation may contain less than 32 bytes, in which case the result is left padded with - * zeros (see {@link #fromHexStringStrict} if this is not what you want). - * @return The value corresponding to {@code str}. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation or contains more than 32 bytes. - */ - static Bytes32 fromHexStringLenient(final String str) { - return wrap(BytesValues.fromRawHexString(str, SIZE, true)); - } - - /** - * Parse an hexadecimal string into a {@link Bytes32}. - * - *

This method is strict in that {@code str} must of an even length. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". That - * representation may contain less than 32 bytes, in which case the result is left padded with - * zeros (see {@link #fromHexStringStrict} if this is not what you want). - * @return The value corresponding to {@code str}. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation, is of an odd length, or contains more than 32 bytes. - */ - static Bytes32 fromHexString(final String str) { - return wrap(BytesValues.fromRawHexString(str, SIZE, false)); - } - - /** - * Parse an hexadecimal string into a {@link Bytes32}. - * - *

This method is extra strict in that {@code str} must of an even length and the provided - * representation must have exactly 32 bytes. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". - * @return The value corresponding to {@code str}. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation, is of an odd length or does not contain exactly 32 bytes. - */ - static Bytes32 fromHexStringStrict(final String str) { - return wrap(BytesValues.fromRawHexString(str, -1, false)); - } - - @Override - default int size() { - return SIZE; - } - - @Override - Bytes32 copy(); - - @Override - MutableBytes32 mutableCopy(); - - /** - * Return a {@link UInt256} that wraps these bytes. - * - *

Note that the returned {@link UInt256} is essentially a "view" of these bytes, and so if - * this value is mutable and is muted, the returned {@link UInt256} will reflect those changes. - * - * @return A {@link UInt256} that wraps these bytes. - */ - default UInt256 asUInt256() { - return UInt256.wrap(this); - } - - /** - * Return a {@link Int256} that wraps these bytes. - * - *

Note that the returned {@link UInt256} is essentially a "view" of these bytes, and so if - * this value is mutable and is muted, the returned {@link UInt256} will reflect those changes. - * - * @return A {@link Int256} that wraps these bytes. - */ - default Int256 asInt256() { - return Int256.wrap(this); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32Backed.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32Backed.java deleted file mode 100644 index db93647a..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32Backed.java +++ /dev/null @@ -1,29 +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.utils.discoveryutils.bytes; - -public interface Bytes32Backed extends BytesBacked { - @Override - Bytes32 getBytes(); -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32s.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32s.java deleted file mode 100644 index d84d9cee..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/Bytes32s.java +++ /dev/null @@ -1,131 +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.utils.discoveryutils.bytes; - -public abstract class Bytes32s { - - private Bytes32s() {} - - public static void and(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - for (int i = 0; i < Bytes32.SIZE; i++) { - result.set(i, (byte) (v1.get(i) & v2.get(i))); - } - } - - public static Bytes32 and(final Bytes32 v1, final Bytes32 v2) { - final MutableBytes32 mb32 = MutableBytes32.create(); - and(v1, v2, mb32); - return mb32; - } - - public static void or(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - for (int i = 0; i < Bytes32.SIZE; i++) { - result.set(i, (byte) (v1.get(i) | v2.get(i))); - } - } - - public static Bytes32 or(final Bytes32 v1, final Bytes32 v2) { - final MutableBytes32 mb32 = MutableBytes32.create(); - or(v1, v2, mb32); - return mb32; - } - - public static void xor(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - for (int i = 0; i < Bytes32.SIZE; i++) { - result.set(i, (byte) (v1.get(i) ^ v2.get(i))); - } - } - - public static Bytes32 xor(final Bytes32 v1, final Bytes32 v2) { - final MutableBytes32 mb32 = MutableBytes32.create(); - xor(v1, v2, mb32); - return mb32; - } - - public static void not(final Bytes32 v, final MutableBytes32 result) { - for (int i = 0; i < Bytes32.SIZE; i++) { - result.set(i, (byte) (~v.get(i))); - } - } - - public static Bytes32 not(final Bytes32 v) { - final MutableBytes32 mb32 = MutableBytes32.create(); - not(v, mb32); - return mb32; - } - - public static String unprefixedHexString(final Bytes32 v) { - return v.toString().substring(2); - } - - public static Bytes32 shiftRight(final Bytes32 v, final int shiftBitCount) { - // Code taken from the Apache 2 licensed library - // https://github.com/patrickfav/bytes-java/blob/master/src/main/java/at/favre/lib/bytes/Util.java - final byte[] byteArray = v.extractArray(); - final int shiftMod = shiftBitCount % 8; - final byte carryMask = (byte) (0xFF << (8 - shiftMod)); - final int offsetBytes = (shiftBitCount / 8); - - int sourceIndex; - for (int i = byteArray.length - 1; i >= 0; i--) { - sourceIndex = i - offsetBytes; - if (sourceIndex < 0) { - byteArray[i] = 0; - } else { - final byte src = byteArray[sourceIndex]; - byte dst = (byte) ((0xff & src) >>> shiftMod); - if (sourceIndex - 1 >= 0) { - dst = (byte) (dst | ((byteArray[sourceIndex - 1] << (8 - shiftMod)) & carryMask)); - } - byteArray[i] = dst; - } - } - return Bytes32.wrap(byteArray); - } - - public static Bytes32 shiftLeft(final Bytes32 v, final int shiftBitCount) { - // Code taken from the Apache 2 licensed library - // https://github.com/patrickfav/bytes-java/blob/master/src/main/java/at/favre/lib/bytes/Util.java - final byte[] byteArray = v.extractArray(); - final int shiftMod = shiftBitCount % 8; - final byte carryMask = (byte) ((1 << shiftMod) - 1); - final int offsetBytes = (shiftBitCount / 8); - - int sourceIndex; - for (int i = 0; i < byteArray.length; i++) { - sourceIndex = i + offsetBytes; - if (sourceIndex >= byteArray.length) { - byteArray[i] = 0; - } else { - final byte src = byteArray[sourceIndex]; - byte dst = (byte) (src << shiftMod); - if (sourceIndex + 1 < byteArray.length) { - dst = (byte) (dst | ((byteArray[sourceIndex + 1] >>> (8 - shiftMod)) & carryMask)); - } - byteArray[i] = dst; - } - } - return Bytes32.wrap(byteArray); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesBacked.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesBacked.java deleted file mode 100644 index 22023a01..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesBacked.java +++ /dev/null @@ -1,29 +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.utils.discoveryutils.bytes; - -public interface BytesBacked { - /** @return The underlying backing bytes of the value. */ - BytesValue getBytes(); -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValue.java deleted file mode 100644 index f0af7e24..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValue.java +++ /dev/null @@ -1,550 +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.utils.discoveryutils.bytes; - -import com.google.common.annotations.VisibleForTesting; -import io.vertx.core.buffer.Buffer; - -import java.nio.ByteBuffer; -import java.security.MessageDigest; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -public interface BytesValue extends Comparable { - - BytesValue EMPTY = wrap(new byte[0]); - - /** - * Wraps the provided byte array as a {@link BytesValue}. - * - *

Note that value is not copied, only wrapped, and thus any future update to {@code value} - * will be reflected in the returned value. - * - * @param value The value to wrap. - * @return A {@link BytesValue} wrapping {@code value}. - */ - static BytesValue wrap(final byte[] value) { - return wrap(value, 0, value.length); - } - - /** - * Wraps a slice/sub-part of the provided array as a {@link BytesValue}. - * - *

Note that value is not copied, only wrapped, and thus any future update to {@code value} - * within the wrapped parts will be reflected in the returned value. - * - * @param value The value to wrap. - * @param offset The index (inclusive) in {@code value} of the first byte exposed by the returned - * value. In other words, you will have {@code wrap(value, o, l).get(0) == value[o]}. - * @param length The length of the resulting value. - * @return A {@link BytesValue} that expose the bytes of {@code value} from {@code offset} - * (inclusive) to {@code offset + length} (exclusive). - * @throws IndexOutOfBoundsException if {@code offset < 0 || (value.length > 0 && offset >= - * value.length)}. - * @throws IllegalArgumentException if {@code length < 0 || offset + length > value.length}. - */ - static BytesValue wrap(final byte[] value, final int offset, final int length) { - return new ArrayWrappingBytesValue(value, offset, length); - } - - /** - * Wraps two other value into a concatenated view. - * - *

Note that the values are not copied, only wrapped, and thus any future update to {@code v1} - * or {@code v2} will be reflected in the returned value. If copying the inputs is desired - * instead, please use {@link BytesValues#concatenate(BytesValue...)}. - * - * @param v1 The first value to wrap. - * @param v2 The second value to wrap. - * @return A value representing a view over the concatenation of {@code v1} and {@code v2}. - */ - static BytesValue wrap(final BytesValue v1, final BytesValue v2) { - return new AbstractBytesValue() { - @Override - public int size() { - return v1.size() + v2.size(); - } - - @Override - public byte get(final int i) { - checkElementIndex(i, size()); - return i < v1.size() ? v1.get(i) : v2.get(i - v1.size()); - } - - @Override - public BytesValue slice(final int i, final int length) { - if (i == 0 && length == size()) return this; - if (length == 0) return BytesValue.EMPTY; - - checkElementIndex(i, size()); - checkArgument( - i + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - i, - i); - - if (i + length < v1.size()) return v1.slice(i, length); - - if (i >= v1.size()) return v2.slice(i - v1.size(), length); - - final MutableBytesValue res = MutableBytesValue.create(length); - final int lengthInV1 = v1.size() - i; - v1.slice(i, lengthInV1).copyTo(res, 0); - v2.slice(0, length - lengthInV1).copyTo(res, lengthInV1); - return res; - } - }; - } - - default BytesValue concat(final BytesValue value) { - return wrap(this, value); - } - - /** - * Wraps a full Vert.x {@link Buffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final Buffer buffer) { - return wrapBuffer(buffer, 0, buffer.length()); - } - - /** - * Wraps a full Vert.x {@link Buffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final Buffer buffer, final int offset) { - return wrapBuffer(buffer, offset, buffer.length() - offset); - } - - /** - * Wraps a slice of a Vert.x {@link Buffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @param size The size of the returned value. - * @return A {@link BytesValue} that exposes the equivalent of {@code buffer.getBytes(offset, - * offset + size)} (but without copying said bytes). - */ - static BytesValue wrapBuffer(final Buffer buffer, final int offset, final int size) { - return MutableBytesValue.wrapBuffer(buffer, offset, size); - } - - /** - * Wraps a {@link ByteBuffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final ByteBuffer buffer) { - return MutableBytesValue.wrapBuffer(buffer, 0, buffer.capacity()); - } - - /** - * Wraps a {@link ByteBuffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @param size The size of the returned value. - * @return A {@link BytesValue} that exposes the equivalent of {@code buffer.getBytes(offset, - * offset + size)} (but without copying said bytes). - */ - static BytesValue wrapBuffer(final ByteBuffer buffer, final int offset, final int size) { - return MutableBytesValue.wrapBuffer(buffer, offset, size); - } - - /** - * Creates a newly allocated value that contains the provided bytes in their provided order. - * - * @param bytes The bytes that must compose the returned value. - * @return A newly allocated value whose bytes are the one from {@code bytes}. - */ - static BytesValue of(final byte... bytes) { - return wrap(bytes); - } - - /** - * Creates a newly allocated value that contains the provided bytes in their provided order. - * - * @param bytes The bytes that must compose the returned value. - * @return A newly allocated value whose bytes are the one from {@code bytes}. - * @throws IllegalArgumentException if any of {@code bytes} would be truncated when storing as a - * byte. - */ - @VisibleForTesting - static BytesValue of(final int... bytes) { - final MutableBytesValue res = MutableBytesValue.create(bytes.length); - for (int i = 0; i < bytes.length; i++) { - final int b = bytes[i]; - checkArgument(b == (((byte) b) & 0xff), "%sth value %s does not fit a byte", i + 1, b); - res.set(i, (byte) b); - } - return res; - } - - /** - * Parse an hexadecimal string into a {@link BytesValue}. - * - *

This method is lenient in that {@code str} may of an odd length, in which case it will - * behave exactly as if it had an additional 0 in front. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". - * @return The value corresponding to {@code str}. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation. - */ - static BytesValue fromHexStringLenient(final String str) { - return BytesValues.fromHexString(str, -1, true); - } - - /** - * Parse an hexadecimal string into a {@link BytesValue} of the provided size. - * - *

This method is lenient in that {@code str} may of an odd length, in which case it will - * behave exactly as if it had an additional 0 in front. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". - * @param destinationSize The size of the returned value, which must be big enough to hold the - * bytes represented by {@code str}. If it is strictly bigger those bytes from {@code str}, - * the returned value will be left padded with zeros. - * @return A value of size {@code destinationSize} corresponding to {@code str} potentially - * left-padded. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation, represents more bytes than {@code destinationSize} or {@code - * destinationSize < 0}. - */ - static BytesValue fromHexStringLenient(final String str, final int destinationSize) { - checkArgument(destinationSize >= 0, "Invalid negative destination size %s", destinationSize); - return BytesValues.fromHexString(str, destinationSize, true); - } - - /** - * Parse an hexadecimal string into a {@link BytesValue}. - * - *

This method is strict in that {@code str} must of an even length. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". - * @return The value corresponding to {@code str}. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation, or is of an odd length. - */ - static BytesValue fromHexString(final String str) { - return BytesValues.fromHexString(str, -1, false); - } - - /** - * Parse an hexadecimal string into a {@link BytesValue}. - * - *

This method is strict in that {@code str} must of an even length. - * - * @param str The hexadecimal string to parse, which may or may not start with "0x". - * @param destinationSize The size of the returned value, which must be big enough to hold the - * bytes represented by {@code str}. If it is strictly bigger those bytes from {@code str}, - * the returned value will be left padded with zeros. - * @return A value of size {@code destinationSize} corresponding to {@code str} potentially - * left-padded. - * @throws IllegalArgumentException if {@code str} does correspond to valid hexadecimal - * representation, or is of an odd length. - * @throws IllegalArgumentException if {@code str} does not correspond to valid hexadecimal - * representation, or is of an odd length, or represents more bytes than {@code - * destinationSize} or {@code destinationSize < 0}. - */ - static BytesValue fromHexString(final String str, final int destinationSize) { - checkArgument(destinationSize >= 0, "Invalid negative destination size %s", destinationSize); - return BytesValues.fromHexString(str, destinationSize, false); - } - - /** @return The number of bytes this value represents. */ - int size(); - - /** - * Retrieves a byte in this value. - * - * @param i The index of the byte to fetch within the value (0-indexed). - * @return The byte at index {@code i} in this value. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - */ - byte get(int i); - - /** - * Retrieves a byte in this value. - * - * @param i The index of the byte to fetch within the value (0-indexed). - * @return The byte at index {@code i} in this value. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - */ - default byte get(final long i) { - return get(Math.toIntExact(i)); - } - - /** - * Retrieves the 4 bytes starting at the provided index in this value as an integer. - * - * @param i The index from which to get the int, which must less than or equal to {@code size() - - * 4}. - * @return An integer whose value is the 4 bytes from this value starting at index {@code i}. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - * @throws IllegalArgumentException if {@code i > size() - 4}. - */ - default int getInt(final int i) { - checkElementIndex(i, size()); - checkArgument( - i <= size() - 4, - "Value of size %s has not enough bytes to read a 4 bytes int from index %s", - size(), - i); - - int value = 0; - value |= (get(i) & 0xFF) << 24; - value |= (get(i + 1) & 0xFF) << 16; - value |= (get(i + 2) & 0xFF) << 8; - value |= (get(i + 3) & 0xFF); - return value; - } - - /** - * Retrieves the 8 bytes starting at the provided index in this value as a long. - * - * @param i The index from which to get the long, which must less than or equal to {@code size() - - * 8}. - * @return A long whose value is the 8 bytes from this value starting at index {@code i}. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - * @throws IllegalArgumentException if {@code i > size() - 8}. - */ - default long getLong(final int i) { - checkElementIndex(i, size()); - checkArgument( - i <= size() - 8, - "Value of size %s has not enough bytes to read a 8 bytes long from index %s", - size(), - i); - - return (((long) getInt(i)) << 32) | (((getInt(i + 4))) & 0xFFFFFFFFL); - } - - /** - * Creates a new value representing (a view of) a slice of the bytes of this value. - * - *

Please note that the resulting slice is only a view and as such maintains a link to the - * underlying full value. So holding a reference to the returned slice may hold more memory than - * the slide represents. Use {@link #copy} on the returned slice if that is not what you want. - * - * @param index The start index for the slice. - * @return A new value providing a view over the bytes from index {@code index} (included) to the - * end. - * @throws IndexOutOfBoundsException if {@code index < 0}. - */ - BytesValue slice(int index); - - /** - * Creates a new value representing (a view of) a slice of the bytes of this value. - * - *

Please note that the resulting slice is only a view and as such maintains a link to the - * underlying full value. So holding a reference to the returned slice may hold more memory than - * the slide represents. Use {@link #copy} on the returned slice if that is not what you want. - * - * @param index The start index for the slice. - * @param length The length of the resulting value. - * @return A new value providing a view over the bytes from index {@code index} (included) to - * {@code index + length} (excluded). - * @throws IllegalArgumentException if {@code length < 0}. - * @throws IndexOutOfBoundsException if {@code index < 0} or {index >= size()} or {index + - * length > size()} . - */ - BytesValue slice(int index, int length); - - /** - * Returns a value equivalent to this one but that is guaranteed to 1) be deeply immutable (that - * is, the underlying value will be immutable) and 2) to not retain more bytes than exposed by the - * value. - * - * @return A value, equals to this one, but deeply immutable and that doesn't retain any - * "unreachable" bytes. For performance reasons, this is allowed to return this value however - * if it already fit those constraints. - */ - BytesValue copy(); - - /** - * Returns a new mutable value initialized with the content of this value. - * - * @return A mutable copy of this value. This will copy bytes, modifying the returned value will - * not modify this value. - */ - MutableBytesValue mutableCopy(); - - /** - * Copy the bytes of this value to the provided mutable one, which must have the same size. - * - * @param destination The mutable value to which to copy the bytes to, which must have the same - * size as this value. If you want to copy value where size differs, you should use {@link - * #slice} and/or {@link MutableBytesValue#mutableSlice} and apply the copy to the result. - * @throws IllegalArgumentException if {@code this.size() != destination.size()}. - */ - void copyTo(MutableBytesValue destination); - - /** - * Copy the bytes of this value to the provided mutable one from a particular offset. - * - *

This is a (potentially slightly more efficient) shortcut for {@code - * copyTo(destination.mutableSlice(destinationOffset, this.size()))}. - * - * @param destination The mutable value to which to copy the bytes to, which must have enough - * bytes from {@code destinationOffset} for the copied value. - * @param destinationOffset The offset in {@code destination} at which the copy starts. - * @throws IllegalArgumentException if the destination doesn't have enough room, that is if {@code - * this.size() > (destination.size() - destinationOffset)}. - */ - void copyTo(MutableBytesValue destination, int destinationOffset); - - /** - * Appends the bytes of this value to the provided Vert.x {@link Buffer}. - * - *

Note that since a Vert.x {@link Buffer} will grow as necessary, this method never fails. - * - * @param buffer The {@link Buffer} to which to append this value. - */ - default void appendTo(final Buffer buffer) { - for (int i = 0; i < size(); i++) { - buffer.appendByte(get(i)); - } - } - - default void copyTo(final byte[] dest, final int srcPos, final int destPos) { - System.arraycopy(getArrayUnsafe(), srcPos, dest, destPos, size() - srcPos); - } - - /** - * Return the number of bytes in common between this set of bytes and another. - * - * @param other The bytes to compare to. - * @return The number of common bytes. - */ - int commonPrefixLength(BytesValue other); - - /** - * Return a slice over the common prefix between this set of bytes and another. - * - * @param other The bytes to compare to. - * @return A slice covering the common prefix. - */ - BytesValue commonPrefix(BytesValue other); - - /** - * Update the provided message digest with the bytes of this value. - * - * @param digest The digest to update. - */ - void update(MessageDigest digest); - - /** - * Whether this value has only zeroed bytes. - * - * @return True if all the bits of this value are zeros. - */ - boolean isZero(); - - /** - * Whether this value is empty, that is is of zero size. - * - * @return {@code true} if {@code size() == 0}, {@code false} otherwise. - */ - default boolean isEmpty() { - return size() == 0; - } - - /** - * Extracts the bytes of this value into a newly allocated byte array. - * - * @return A newly allocated byte array with the same content than this value. - */ - default byte[] extractArray() { - final int size = size(); - final byte[] array = new byte[size]; - for (int i = 0; i < size; i++) { - array[i] = get(i); - } - return array; - } - - /** - * Get the bytes represented by this value as byte array. - * - *

Contrarily to {@link #extractArray()}, this may avoid allocating a new array and directly - * return the backing array of this value if said value is array backed and doing so is possible. - * As such, modifications to the returned array may or may not impact this value. As such, this - * method should be used with care and hence the "unsafe" moniker. - * - * @return A byte array with the same content than this value, which may or may not be the direct - * backing of this value. - */ - default byte[] getArrayUnsafe() { - return extractArray(); - } - - @Override - default int compareTo(final BytesValue other) { - final int minSize = Math.min(size(), other.size()); - for (int i = 0; i < minSize; i++) { - // Using integer comparison to basically simulate unsigned byte comparison - final int cmp = Integer.compare(get(i) & 0xFF, other.get(i) & 0xFF); - if (cmp != 0) { - return cmp; - } - } - return Integer.compare(size(), other.size()); - } - - /** - * Returns the hexadecimal string representation of this value. - * - * @return The hexadecimal representation of this value, starting with "0x". - */ - @Override - String toString(); -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValueRLPOutput.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValueRLPOutput.java deleted file mode 100644 index 341e6768..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValueRLPOutput.java +++ /dev/null @@ -1,42 +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.utils.discoveryutils.bytes; - -public class BytesValueRLPOutput extends AbstractRLPOutput { - /** - * Computes the final encoded data. - * - * @return A value containing the data written to this output RLP-encoded. - */ - public BytesValue encoded() { - final int size = encodedSize(); - if (size == 0) { - return BytesValue.EMPTY; - } - - final MutableBytesValue output = MutableBytesValue.create(size); - writeEncoded(output); - return output; - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValues.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValues.java deleted file mode 100644 index 78814f4a..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/BytesValues.java +++ /dev/null @@ -1,295 +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.utils.discoveryutils.bytes; - -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; - -import static com.google.common.base.Preconditions.checkArgument; - -public abstract class BytesValues { - - private static final int MAX_UNSIGNED_BYTE = (1 << 8) - 1; - private static final int MAX_UNSIGNED_SHORT = (1 << 16) - 1; - private static final long MAX_UNSIGNED_INT = (1L << 32) - 1; - - private BytesValues() {} - - private static byte b(final long l) { - return (byte) (l & 0xFF); - } - - /** - * Returns the number of zero-valued bytes in the bytes value. - * - * @param value The value of which to count tye zero-valued bytes within - * @return the number of zero-valued bytes in the bytes value. - */ - public static int countZeros(final BytesValue value) { - int count = 0; - for (int i = 0; i < value.size(); i++) { - if (value.get(i) == 0) { - ++count; - } - } - return count; - } - - /** - * Return a slice of the provided value representing the same value but without any potential - * leading zeros. - * - * @param value The value of which to trim leading zeros. - * @return {@code value} if its left-most byte is non zero, or a slice that exclude any leading - * zeros. Note that if {@code value} contains only zeros, it will return an empty value. - */ - public static BytesValue trimLeadingZeros(final BytesValue value) { - final int toTrim = leadingZeros(value); - return value.slice(toTrim); - } - - /** - * Returns the smallest bytes value whose bytes correspond to the provided long. That is, the - * returned value may be of size less than 8 if the provided int has leading zero bytes. - * - * @param l The long from which to create the bytes value. - * @return The minimal bytes representation corresponding to {@code l}. - */ - public static BytesValue toMinimalBytes(final long l) { - if (l == 0) return BytesValue.EMPTY; - - final int zeros = Long.numberOfLeadingZeros(l); - final int resultBytes = 8 - (zeros / 8); - - final byte[] result = new byte[resultBytes]; - int shift = 0; - for (int i = 0; i < resultBytes; i++) { - result[resultBytes - i - 1] = b(l >> shift); - shift += 8; - } - return BytesValue.wrap(result); - } - - /** - * Returns a 1 byte value corresponding to the provided value interpreted as an unsigned byte - * value. - * - * @param v The value, which must fit an unsigned byte. - * @return A single byte value corresponding to {@code v}. - * @throws IllegalArgumentException if {@code v < 0} or {@code v} is too big to fit an unsigned - * byte (that is, if {@code v >= (1 << 8)}). - */ - public static BytesValue ofUnsignedByte(final int v) { - checkArgument( - v >= 0 && v <= MAX_UNSIGNED_BYTE, - "Value %s cannot be represented as an unsigned byte (it is negative or too big)", - v); - final byte[] res = new byte[1]; - res[0] = b(v); - return BytesValue.wrap(res); - } - - /** - * Returns a 2 bytes value corresponding to the provided value interpreted as an unsigned short - * value. - * - * @param v The value, which must fit an unsigned short. - * @return A 2 bytes value corresponding to {@code v}. - * @throws IllegalArgumentException if {@code v < 0} or {@code v} is too big to fit an unsigned - * 2-bytes short (that is, if {@code v >= (1 << 16)}). - */ - public static BytesValue ofUnsignedShort(final int v) { - checkArgument( - v >= 0 && v <= MAX_UNSIGNED_SHORT, - "Value %s cannot be represented as an unsigned short (it is negative or too big)", - v); - final byte[] res = new byte[2]; - res[0] = b(v >> 8); - res[1] = b(v); - return BytesValue.wrap(res); - } - - /** - * Returns a 4 bytes value corresponding to the provided value interpreted as an unsigned int - * value. - * - * @param v The value, which must fit an unsigned int. - * @return A 4 bytes value corresponding to {@code v}. - * @throws IllegalArgumentException if {@code v < 0} or {@code v} is too big to fit an unsigned - * 4-bytes int (that is, if {@code v >= (1L << 32)}). - */ - public static BytesValue ofUnsignedInt(final long v) { - checkArgument( - v >= 0 && v <= MAX_UNSIGNED_INT, - "Value %s cannot be represented as an unsigned int (it is negative or too big)", - v); - final byte[] res = new byte[4]; - res[0] = b(v >> 24); - res[1] = b(v >> 16); - res[2] = b(v >> 8); - res[3] = b(v); - return BytesValue.wrap(res); - } - - /** - * Creates a newly allocated value containing the concatenation of the values provided. - * - * @param values The value to copy/concatenate. - * @return A newly allocated value containing the result of containing the value from {@code - * values} in their provided order. - */ - public static BytesValue concatenate(final BytesValue... values) { - int size = 0; - for (final BytesValue value : values) { - size += value.size(); - } - - final MutableBytesValue result = MutableBytesValue.create(size); - int offset = 0; - for (final BytesValue value : values) { - value.copyTo(result, offset); - offset += value.size(); - } - return result; - } - - /** - * The BigInteger corresponding to interpreting the provided bytes as an unsigned integer. - * - * @param bytes The bytes to interpret. - * @return A positive (or zero) {@link BigInteger} corresponding to this value interpreted as an - * unsigned integer representation. - */ - public static BigInteger asUnsignedBigInteger(final BytesValue bytes) { - return new BigInteger(1, bytes.getArrayUnsafe()); - } - - /** - * Decode the bytes as a UTF-8 String. - * - * @param bytes The bytes to decode. - * @return A utf-8 string corresponding to the bytes data. - */ - public static String asString(final BytesValue bytes) { - return new String(bytes.extractArray(), StandardCharsets.UTF_8); - } - - /** - * The BigInteger corresponding to interpreting the provided bytes as a signed integer. - * - * @param bytes The bytes to interpret. - * @return A {@link BigInteger} corresponding to this value interpreted as a two's-complement - * integer representation. - */ - public static BigInteger asSignedBigInteger(final BytesValue bytes) { - // An empty byte value is an invalid magnitude as far as BigInteger is concerned because it - // wants at least 1 sign bit. - if (bytes.size() == 0) { - return BigInteger.ZERO; - } - return new BigInteger(bytes.getArrayUnsafe()); - } - - // In Java9, this could be moved to BytesValue and made private - static BytesValue fromHexString(final String str, final int destSize, final boolean lenient) { - return BytesValue.wrap(fromRawHexString(str, destSize, lenient)); - } - - static byte[] fromRawHexString( - final String str, final int taintedDestSize, final boolean lenient) { - String hex = str; - if (str.startsWith("0x")) { - hex = str.substring(2); - } - - int len = hex.length(); - int idxShift = 0; - if (len % 2 != 0) { - if (!lenient) { - throw new IllegalArgumentException("Invalid odd-length hex binary representation " + str); - } - - hex = "0" + hex; - len += 1; - idxShift = 1; - } - - final int size = len / 2; - final int destSize; - - if (taintedDestSize < 0) { - destSize = size; - } else { - destSize = taintedDestSize; - checkArgument( - size <= destSize, - "Hex value %s is too big: expected at most %s bytes but got %s", - str, - destSize, - size); - } - - final byte[] out = new byte[destSize]; - - final int destOffset = (destSize - size); - for (int i = 0; i < len; i += 2) { - final int h = hexToBin(hex.charAt(i)); - final int l = hexToBin(hex.charAt(i + 1)); - if (h == -1) { - throw new IllegalArgumentException( - String.format( - "Illegal character '%c' found at index %d in hex binary representation %s", - hex.charAt(i), i - idxShift, str)); - } - if (l == -1) { - throw new IllegalArgumentException( - String.format( - "Illegal character '%c' found at index %d in hex binary representation %s", - hex.charAt(i + 1), i + 1 - idxShift, str)); - } - - out[destOffset + (i / 2)] = (byte) (h * 16 + l); - } - return out; - } - - private static int hexToBin(final char ch) { - if ('0' <= ch && ch <= '9') { - return ch - 48; - } else if ('A' <= ch && ch <= 'F') { - return ch - 65 + 10; - } else { - return 'a' <= ch && ch <= 'f' ? ch - 97 + 10 : -1; - } - } - - private static int leadingZeros(final BytesValue bytes) { - for (int i = 0; i < bytes.size(); i++) { - if (bytes.get(i) != 0) { - return i; - } - } - return bytes.size(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytes32.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytes32.java deleted file mode 100644 index 1cf40625..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytes32.java +++ /dev/null @@ -1,47 +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.utils.discoveryutils.bytes; - - -class MutableArrayWrappingBytes32 extends MutableArrayWrappingBytesValue implements MutableBytes32 { - - MutableArrayWrappingBytes32(final byte[] bytes) { - this(bytes, 0); - } - - MutableArrayWrappingBytes32(final byte[] bytes, final int offset) { - super(bytes, offset, SIZE); - } - - @Override - public Bytes32 copy() { - // We *must* override this method because ArrayWrappingBytes32 assumes that it is the case. - return new ArrayWrappingBytes32(arrayCopy()); - } - - @Override - public MutableBytes32 mutableCopy() { - return new MutableArrayWrappingBytes32(arrayCopy()); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytesValue.java deleted file mode 100644 index f99b5678..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableArrayWrappingBytesValue.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.utils.discoveryutils.bytes; - -import java.util.Arrays; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -class MutableArrayWrappingBytesValue extends ArrayWrappingBytesValue implements MutableBytesValue { - - MutableArrayWrappingBytesValue(final byte[] bytes) { - super(bytes); - } - - MutableArrayWrappingBytesValue(final byte[] bytes, final int offset, final int length) { - super(bytes, offset, length); - } - - @Override - public void set(final int i, final byte b) { - // Check bounds because while the array access would throw, the error message would be confusing - // for the caller. - checkElementIndex(i, size()); - this.bytes[offset + i] = b; - } - - @Override - public MutableBytesValue mutableSlice(final int i, final int length) { - if (i == 0 && length == size()) return this; - if (length == 0) return MutableBytesValue.EMPTY; - - checkElementIndex(i, size()); - checkArgument( - i + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - i, - i); - return length == Bytes32.SIZE - ? new MutableArrayWrappingBytes32(bytes, offset + i) - : new MutableArrayWrappingBytesValue(bytes, offset + i, length); - } - - @Override - public void fill(final byte b) { - Arrays.fill(bytes, offset, offset + length, b); - } - - @Override - public BytesValue copy() { - // We *must* override this method because ArrayWrappingBytesValue assumes that it is the case. - return new ArrayWrappingBytesValue(arrayCopy()); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBufferWrappingBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBufferWrappingBytesValue.java deleted file mode 100644 index 47b11cb6..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBufferWrappingBytesValue.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.utils.discoveryutils.bytes; - -import io.vertx.core.buffer.Buffer; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -class MutableBufferWrappingBytesValue extends AbstractBytesValue implements MutableBytesValue { - - private final Buffer buffer; - private final int offset; - private final int size; - - MutableBufferWrappingBytesValue(final Buffer buffer, final int offset, final int size) { - checkArgument(size >= 0, "Invalid negative length provided"); - if (size > 0) { - checkElementIndex(offset, buffer.length()); - } - checkArgument( - offset + size <= buffer.length(), - "Provided length %s is too big: the buffer has size %s and has only %s bytes from %s", - size, - buffer.length(), - buffer.length() - offset, - offset); - - this.buffer = buffer; - this.offset = offset; - this.size = size; - } - - - - @Override - public int size() { - return size; - } - - @Override - public byte get(final int i) { - checkElementIndex(i, size()); - return buffer.getByte(offset + i); - } - - @Override - public void set(final int i, final byte b) { - checkElementIndex(i, size()); - buffer.setByte(offset + i, b); - } - - @Override - public MutableBytesValue mutableSlice(final int index, final int length) { - if (index == 0 && length == size()) { - return this; - } - if (length == 0) { - return MutableBytesValue.EMPTY; - } - - checkElementIndex(index, size()); - checkArgument( - index + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - index, - index); - - return new MutableBufferWrappingBytesValue(buffer, offset + index, length); - } - - @Override - public BytesValue slice(final int index, final int length) { - return mutableSlice(index, length); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufWrappingBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufWrappingBytesValue.java deleted file mode 100644 index ca615086..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufWrappingBytesValue.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.utils.discoveryutils.bytes; - -import io.netty.buffer.ByteBuf; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -class MutableByteBufWrappingBytesValue extends AbstractBytesValue implements MutableBytesValue { - - private final ByteBuf buffer; - private final int offset; - private final int size; - - MutableByteBufWrappingBytesValue(final ByteBuf buffer, final int offset, final int size) { - checkArgument(size >= 0, "Invalid negative length provided"); - if (size > 0) { - checkElementIndex(offset, buffer.writerIndex()); - } - checkArgument( - offset + size <= buffer.writerIndex(), - "Provided length %s is too big: the buffer has size %s and has only %s bytes from %s", - size, - buffer.writerIndex(), - buffer.writerIndex() - offset, - offset); - - this.buffer = buffer; - this.offset = offset; - this.size = size; - } - - MutableByteBufWrappingBytesValue(final ByteBuf buffer) { - this(buffer, 0, buffer.writerIndex()); - } - - @Override - public int size() { - return size; - } - - @Override - public byte get(final int i) { - return buffer.getByte(offset + i); - } - - @Override - public void set(final int i, final byte b) { - buffer.setByte(offset + i, b); - } - - @Override - public MutableBytesValue mutableSlice(final int index, final int length) { - if (index == 0 && length == size) { - return this; - } - if (length == 0) { - return MutableBytesValue.EMPTY; - } - - checkElementIndex(index, size); - checkArgument( - index + length <= size, - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size - index, - index); - - return new MutableByteBufWrappingBytesValue(buffer, offset + index, length); - } - - @Override - public BytesValue slice(final int index, final int length) { - return mutableSlice(index, length); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufferWrappingBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufferWrappingBytesValue.java deleted file mode 100644 index 7308efdc..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableByteBufferWrappingBytesValue.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.utils.discoveryutils.bytes; - -import java.nio.ByteBuffer; - -import static com.google.common.base.Preconditions.*; - -public class MutableByteBufferWrappingBytesValue extends AbstractBytesValue - implements MutableBytesValue { - - protected final ByteBuffer bytes; - protected final int offset; - protected final int size; - - /** - * Wraps a ByteBuffer given absolute values for offset. - * - * @param bytes the source byte buffer - * @param offset the absolute offset where this value should begin - * @param size the number of bytes to include in this value - */ - MutableByteBufferWrappingBytesValue(final ByteBuffer bytes, final int offset, final int size) { - int bytesSize = bytes.capacity(); - checkNotNull(bytes, "Invalid 'null' byte buffer provided"); - checkArgument(size >= 0, "Invalid negative length provided"); - if (size > 0) { - checkElementIndex(offset, bytesSize); - } - checkArgument( - offset + size <= bytesSize, - "Provided length %s is too big: the value has only %s bytes from offset %s", - size, - bytesSize - offset, - offset); - - this.bytes = bytes; - this.offset = offset; - this.size = size; - } - - @Override - public int size() { - return size; - } - - @Override - public byte get(final int i) { - checkElementIndex(i, size()); - return bytes.get(offset + i); - } - - @Override - public BytesValue slice(final int index, final int length) { - if (index == 0 && length == size()) { - return this; - } - if (length == 0) { - return BytesValue.EMPTY; - } - - checkElementIndex(index, size()); - checkArgument( - index + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - index, - index); - - return new MutableByteBufferWrappingBytesValue(bytes, offset + index, length); - } - - @Override - public void set(final int i, final byte b) { - checkElementIndex(i, size()); - bytes.put(offset + i, b); - } - - @Override - public MutableBytesValue mutableSlice(final int index, final int length) { - if (index == 0 && length == size()) { - return this; - } - if (length == 0) { - return MutableBytesValue.EMPTY; - } - - checkElementIndex(index, size()); - checkArgument( - index + length <= size(), - "Provided length %s is too big: the value has size %s and has only %s bytes from %s", - length, - size(), - size() - index, - index); - - return new MutableByteBufferWrappingBytesValue(bytes, offset + index, length); - } - - @Override - public byte[] getArrayUnsafe() { - if (bytes.hasArray() && offset == 0 && size == bytes.capacity() && bytes.arrayOffset() == 0) { - return bytes.array(); - } - - return super.getArrayUnsafe(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytes32.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytes32.java deleted file mode 100644 index 711b3b04..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytes32.java +++ /dev/null @@ -1,151 +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.utils.discoveryutils.bytes; - -import java.security.MessageDigest; - -import static com.google.common.base.Preconditions.checkArgument; - -public interface MutableBytes32 extends MutableBytesValue, Bytes32 { - - /** - * Wraps a 32 bytes array as a mutable 32 bytes value. - * - *

This method behave exactly as {@link Bytes32#wrap(byte[])} except that the result is a - * mutable. - * - * @param value The value to wrap. - * @return A {@link MutableBytes32} wrapping {@code value}. - * @throws IllegalArgumentException if {@code value.length != 32}. - */ - static MutableBytes32 wrap(final byte[] value) { - return new MutableArrayWrappingBytes32(value); - } - - /** - * Creates a new mutable 32 bytes value. - * - * @return A newly allocated {@link MutableBytesValue}. - */ - static MutableBytes32 create() { - return new MutableArrayWrappingBytes32(new byte[SIZE]); - } - - /** - * Wraps an existing {@link MutableBytesValue} of size 32 as a mutable 32 bytes value. - * - *

This method does no copy the provided bytes and so any mutation on {@code value} will also - * be reflected in the value returned by this method. If a copy is desirable, this can be simply - * achieved with calling {@link BytesValue#copyTo(MutableBytesValue)} with a newly created {@link - * MutableBytes32} as destination to the copy. - * - * @param value The value to wrap. - * @return A {@link MutableBytes32} wrapping {@code value}. - * @throws IllegalArgumentException if {@code value.size() != 32}. - */ - static MutableBytes32 wrap(final MutableBytesValue value) { - checkArgument(value.size() == SIZE, "Expected %s bytes but got %s", SIZE, value.size()); - return new MutableBytes32() { - @Override - public void set(final int i, final byte b) { - value.set(i, b); - } - - @Override - public MutableBytesValue mutableSlice(final int i, final int length) { - return value.mutableSlice(i, length); - } - - @Override - public byte get(final int i) { - return value.get(i); - } - - @Override - public BytesValue slice(final int index) { - return value.slice(index); - } - - @Override - public BytesValue slice(final int index, final int length) { - return value.slice(index, length); - } - - @Override - public Bytes32 copy() { - return Bytes32.wrap(value.extractArray()); - } - - @Override - public MutableBytes32 mutableCopy() { - return MutableBytes32.wrap(value.extractArray()); - } - - @Override - public void copyTo(final MutableBytesValue destination) { - value.copyTo(destination); - } - - @Override - public void copyTo(final MutableBytesValue destination, final int destinationOffset) { - value.copyTo(destination, destinationOffset); - } - - @Override - public int commonPrefixLength(final BytesValue other) { - return value.commonPrefixLength(other); - } - - @Override - public BytesValue commonPrefix(final BytesValue other) { - return value.commonPrefix(other); - } - - @Override - public void update(final MessageDigest digest) { - value.update(digest); - } - - @Override - public boolean isZero() { - return value.isZero(); - } - - @Override - public boolean equals(final Object other) { - return value.equals(other); - } - - @Override - public int hashCode() { - return value.hashCode(); - } - - @Override - public String toString() { - return value.toString(); - } - }; - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytesValue.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytesValue.java deleted file mode 100644 index 695ada8c..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/MutableBytesValue.java +++ /dev/null @@ -1,260 +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.utils.discoveryutils.bytes; - -import io.netty.buffer.ByteBuf; -import io.vertx.core.buffer.Buffer; - -import java.nio.ByteBuffer; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkElementIndex; - -public interface MutableBytesValue extends BytesValue { - MutableBytesValue EMPTY = wrap(new byte[0]); - - /** - * Creates a new mutable byte value of the provided size. - * - * @param size The size of the returned value. - * @return A newly allocated {@link MutableBytesValue}. - */ - static MutableBytesValue create(final int size) { - return new MutableArrayWrappingBytesValue(new byte[size]); - } - - /** - * Wraps a byte array as a mutable byte value. - * - *

This method behave exactly as {@link BytesValue#wrap(byte[])} except that the result is - * mutable. - * - * @param value The value to wrap. - * @return A {@link MutableBytesValue} wrapping {@code value}. - */ - static MutableBytesValue wrap(final byte[] value) { - return new MutableArrayWrappingBytesValue(value); - } - - /** - * /** Wraps a byte array as a mutable byte value. - * - *

This method behave exactly as {@link BytesValue#wrap(byte[],int,int)} except that the result - * is mutable. - * - * @param value The value to wrap. - * @param offset The index (inclusive) in {@code value} of the first byte exposed by the returned - * value. In other words, you will have {@code wrap(value, o, l).get(0) == value[o]}. - * @param length The length of the resulting value. - * @return A {@link BytesValue} that expose the bytes of {@code value} from {@code offset} - * (inclusive) to {@code offset + length} (exclusive). - * @throws IndexOutOfBoundsException if {@code offset < 0 || (value.length > 0 && offset >= - * value.length)}. - * @throws IllegalArgumentException if {@code length < 0 || offset + length > value.length}. - */ - static MutableBytesValue wrap(final byte[] value, final int offset, final int length) { - return new MutableArrayWrappingBytesValue(value, offset, length); - } - - /** - * Wraps a full Vert.x {@link Buffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final Buffer buffer) { - return wrapBuffer(buffer, 0, buffer.length()); - } - - /** - * Wraps a slice of a Vert.x {@link Buffer} as a {@link MutableBytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value, and any change to the returned value will be reflected in the - * buffer. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @param size The size of the returned value. - * @return A {@link MutableBytesValue} that exposes (reading and writing) the bytes in {@code - * buffer} from {@code offset} (inclusive) to {@code offset + size} (exclusive). - */ - static MutableBytesValue wrapBuffer(final Buffer buffer, final int offset, final int size) { - if (size == 0) { - return EMPTY; - } - return new MutableBufferWrappingBytesValue(buffer, offset, size); - } - - /** - * Wraps a full Netty {@link ByteBuf} as a {@link BytesValue}. - * - * @param buffer The buffer to wrap. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final ByteBuf buffer) { - return wrapBuffer(buffer, buffer.readerIndex(), buffer.readableBytes()); - } - - /** - * Wraps a slice of a Netty {@link ByteBuf} as a {@link MutableBytesValue}. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @param size The size of the returned value. - * @return A {@link MutableBytesValue} that exposes (reading and writing) the bytes in {@code - * buffer} from {@code offset} (inclusive) to {@code offset + size} (exclusive). - */ - static MutableBytesValue wrapBuffer(final ByteBuf buffer, final int offset, final int size) { - if (size == 0) { - return EMPTY; - } - return new MutableByteBufWrappingBytesValue(buffer, offset, size); - } - - /** - * Wraps a {@link ByteBuffer} as a {@link BytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value. - * - * @param buffer The buffer to wrap. - * @return A {@link BytesValue} that exposes the bytes of {@code buffer}. - */ - static BytesValue wrapBuffer(final ByteBuffer buffer) { - return MutableBytesValue.wrapBuffer(buffer, 0, buffer.capacity()); - } - - /** - * Wraps a slice of a {@link ByteBuffer} as a {@link MutableBytesValue}. - * - *

Note that as the buffer is wrapped, any change to the content of that buffer may be - * reflected in the returned value, and any change to the returned value will be reflected in the - * buffer. - * - * @param buffer The buffer to wrap. - * @param offset The offset in {@code buffer} from which to expose the bytes in the returned - * value. That is, {@code wrapBuffer(buffer, i, 1).get(0) == buffer.getByte(i)}. - * @param size The size of the returned value. - * @return A {@link MutableBytesValue} that exposes (reading and writing) the bytes in {@code - * buffer} from {@code offset} (inclusive) to {@code offset + size} (exclusive). - */ - static MutableBytesValue wrapBuffer(final ByteBuffer buffer, final int offset, final int size) { - if (size == 0) { - return EMPTY; - } - return new MutableByteBufferWrappingBytesValue(buffer, offset, size); - } - - /** - * Sets a particular byte in this value. - * - * @param i The index of the byte to set. - * @param b The value to set that byte to. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - */ - void set(int i, byte b); - - /** - * Sets the 4 bytes starting at the provided index in this value to the provided integer value. - * - * @param i The index from which to set the int, which must less than or equal to {@code size() - - * 4}. - * @param value The value to set. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - * @throws IllegalArgumentException if {@code i > size() - 4}. - */ - default void setInt(final int i, final int value) { - checkElementIndex(i, size()); - checkArgument( - i <= size() - 4, - "Value of size %s has not enough bytes to write a 4 bytes int from index %s", - size(), - i); - - set(i, (byte) (value >>> 24)); - set(i + 1, (byte) ((value >>> 16) & 0xFF)); - set(i + 2, (byte) ((value >>> 8) & 0xFF)); - set(i + 3, (byte) (value & 0xFF)); - } - - /** - * Sets the 8 bytes starting at the provided index in this value to the provided long value. - * - * @param i The index from which to set the long, which must less than or equal to {@code size() - - * 8}. - * @param value The value to set. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()}. - * @throws IllegalArgumentException if {@code i > size() - 8}. - */ - default void setLong(final int i, final long value) { - checkElementIndex(i, size()); - checkArgument( - i <= size() - 8, - "Value of size %s has not enough bytes to write a 8 bytes long from index %s", - size(), - i); - - setInt(i, (int) (value >>> 32)); - setInt(i + 4, (int) value); - } - - /** - * Creates a new value representing a mutable slice of the bytes of this value. - * - *

Please note that the resulting slice is only a view and as such maintains a link to the - * underlying full value. So holding a reference to the returned slice may hold more memory than - * the slide represents. Use {@link #copy} on the returned slice if that is not what you want. - * - * @param i The start index for the slice. - * @param length The length of the resulting value. - * @return A new mutable view over the bytes of this value from index {@code i} (included) to - * index {@code i + length} (excluded). - * @throws IllegalArgumentException if {@code length < 0}. - * @throws IndexOutOfBoundsException if {@code i < 0} or {i >= size()} or {i + length > - * size()} . - */ - MutableBytesValue mutableSlice(int i, int length); - - /** - * Fills all the bytes of this value with the provided byte. - * - * @param b The byte to use to fill the value. - */ - default void fill(final byte b) { - for (int i = 0; i < size(); i++) { - set(i, b); - } - } - - /** Clears all the bytes (set to 0) of this value. */ - default void clear() { - fill((byte) 0); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLP.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/RLP.java deleted file mode 100644 index 116559ed..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLP.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.utils.discoveryutils.bytes; - -import io.vertx.core.buffer.Buffer; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.uint.BytesValueRLPInput; -import io.xdag.utils.discoveryutils.bytes.uint.RLPException; - -import java.util.function.Consumer; - -import static java.lang.String.format; -import static io.xdag.utils.discoveryutils.bytes.RLPDecodingHelpers.extractSize; -import static io.xdag.utils.discoveryutils.bytes.RLPEncodingHelpers.*; - -public abstract class RLP { - private RLP() {} - - /** The RLP encoding of a single empty value, also known as RLP null. */ - public static final BytesValue NULL = encodeOne(BytesValue.EMPTY); - - public static final BytesValue EMPTY_LIST; - - static { - final BytesValueRLPOutput out = new BytesValueRLPOutput(); - out.startList(); - out.endList(); - EMPTY_LIST = out.encoded(); - } - - /** - * Creates a new {@link RLPInput} suitable for decoding the provided RLP encoded value. - * - *

The created input is strict, in that exceptions will be thrown for any malformed input, - * either by this method or by future reads from the returned input. - * - * @param encoded The RLP encoded data for which to create a {@link RLPInput}. - * @return A newly created {@link RLPInput} to decode {@code encoded}. - * @throws MalformedRLPInputException if {@code encoded} doesn't contain a single RLP encoded item - * (item that can be a list itself). Note that more deeply nested corruption/malformation of - * the input will not be detected by this method call, but will be later when the input is - * read. - */ - public static RLPInput input(final BytesValue encoded) { - return new BytesValueRLPInput(encoded, false); - } - - /** - * Creates a new {@link RLPInput} suitable for decoding an RLP value encoded in the provided - * Vert.x {@link Buffer}. - * - *

The created input is strict, in that exceptions will be thrown for any malformed input, - * either by this method or by future reads from the returned input. - * - * @param buffer A buffer containing the RLP encoded data to decode. - * @param offset The offset in {@code encoded} at which the data to decode starts. - * @return A newly created {@link RLPInput} to decode RLP data in {@code encoded} from {@code - * offset}. - * @throws MalformedRLPInputException if {@code encoded} doesn't contain a properly encoded RLP - * item. Note that this only detect malformation on the main item at {@code offset}, but more - * deeply nested corruption/malformation of the input will not be detected by this method - * call, but only later when the input is read. - */ - public static BytesValueRLPInput input(final Buffer buffer, final int offset) { - return new BytesValueRLPInput(BytesValue.wrapBuffer(buffer, offset), false, false); - } - - /** - * Creates a {@link RLPOutput}, pass it to the provided consumer for writing, and then return the - * RLP encoded result of that writing. - * - *

This method is a convenience method that is mostly meant for use with class that have a - * method to write to an {@link RLPOutput}. For instance: - * - *

{@code
-     * class Foo {
-     *   public void writeTo(RLPOutput out) {
-     *     //... write some data to out ...
-     *   }
-     * }
-     *
-     * Foo f = ...;
-     * // RLP encode f
-     * BytesValue encoded = RLPs.encode(f::writeTo);
-     * }
- * - * @param writer A method that given an {@link RLPOutput}, writes some data to it. - * @return The RLP encoding of the data written by {@code writer}. - */ - public static BytesValue encode(final Consumer writer) { - final BytesValueRLPOutput out = new BytesValueRLPOutput(); - writer.accept(out); - return out.encoded(); - } - - /** - * Encodes a single binary value into RLP. - * - *

This is equivalent (but possibly more efficient) to: - * - *

-     * {
-     *   @code
-     *   BytesValueRLPOutput out = new BytesValueRLPOutput();
-     *   out.writeBytesValue(value);
-     *   return out.encoded();
-     * }
-     * 
- * - * So note in particular that the value is encoded as is (and so not as a scalar in particular). - * - * @param value The value to encode. - * @return The RLP encoding containing only {@code value}. - */ - public static BytesValue encodeOne(final BytesValue value) { - if (isSingleRLPByte(value)) return value; - - final MutableBytesValue res = MutableBytesValue.create(elementSize(value)); - writeElement(value, res, 0); - return res; - } - - /** - * Decodes an RLP-encoded value assuming it contains a single non-list item. - * - *

This is equivalent (but possibly more efficient) to: - * - *

{@code
-     * return input(value).readBytesValue();
-     * }
- * - * So note in particular that the value is decoded as is (and so not as a scalar in particular). - * - * @param encodedValue The encoded RLP value. - * @return The single value encoded in {@code encodedValue}. - * @throws RLPException if {@code encodedValue} is not a valid RLP encoding or if it does not - * contains a single non-list item. - */ - public static BytesValue decodeOne(final BytesValue encodedValue) { - if (encodedValue.size() == 0) { - throw new RLPException("Invalid empty input for RLP decoding"); - } - - final int prefix = encodedValue.get(0) & 0xFF; - final RLPDecodingHelpers.Kind kind = RLPDecodingHelpers.Kind.of(prefix); - if (kind.isList()) { - throw new RLPException(format("Invalid input: value %s is an RLP list", encodedValue)); - } - - if (kind == RLPDecodingHelpers.Kind.BYTE_ELEMENT) { - return encodedValue; - } - - final int offset; - final int size; - if (kind == RLPDecodingHelpers.Kind.SHORT_ELEMENT) { - offset = 1; - size = prefix - 0x80; - } else { - final int sizeLength = prefix - 0xb7; - if (1 + sizeLength > encodedValue.size()) { - throw new RLPException( - format( - "Malformed RLP input: not enough bytes to read size of " - + "long item in %s: expected %d bytes but only %d", - encodedValue, sizeLength + 1, encodedValue.size())); - } - offset = 1 + sizeLength; - size = extractSize(encodedValue::get, 1, sizeLength); - } - if (offset + size != encodedValue.size()) { - throw new RLPException( - format( - "Malformed RLP input: %s should be of size %d according to " - + "prefix byte but of size %d", - encodedValue, offset + size, encodedValue.size())); - } - return encodedValue.slice(offset, size); - } - - /** - * Validates that the provided value is a valid RLP encoding. - * - * @param encodedValue The value to check. - * @throws RLPException if {@code encodedValue} is not a valid RLP encoding. - */ - public static void validate(final BytesValue encodedValue) { - final RLPInput in = input(encodedValue); - while (!in.isDone()) { - if (in.nextIsList()) { - in.enterList(); - } else if (in.isEndOfCurrentList()) { - in.leaveList(); - } else { - // Skip does as much validation as can be done in general, without allocating anything. - in.skipNext(); - } - } - } - - /** - * Given a {@link BytesValue} containing rlp-encoded data, determines the full length of the - * encoded value (including the prefix) by inspecting the prefixed metadata. - * - * @param value the rlp-encoded byte string - * @return the length of the encoded data, according to the prefixed metadata - */ - public static int calculateSize(final BytesValue value) { - return RLPDecodingHelpers.rlpElementMetadata(value::get, value.size(), 0).getEncodedSize(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPDecodingHelpers.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPDecodingHelpers.java deleted file mode 100644 index 54c04a2c..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPDecodingHelpers.java +++ /dev/null @@ -1,209 +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.utils.discoveryutils.bytes; - -import io.xdag.utils.discoveryutils.MalformedRLPInputException; -import io.xdag.utils.discoveryutils.bytes.uint.CorruptedRLPInputException; -import io.xdag.utils.discoveryutils.bytes.uint.RLPException; - -import java.util.function.IntUnaryOperator; -import java.util.function.LongUnaryOperator; - -public class RLPDecodingHelpers { - - /** The kind of items an RLP item can be. */ - public enum Kind { - BYTE_ELEMENT, - SHORT_ELEMENT, - LONG_ELEMENT, - SHORT_LIST, - LONG_LIST; - - static Kind of(final int prefix) { - if (prefix <= 0x7F) { - return Kind.BYTE_ELEMENT; - } else if (prefix <= 0xb7) { - return Kind.SHORT_ELEMENT; - } else if (prefix <= 0xbf) { - return Kind.LONG_ELEMENT; - } else if (prefix <= 0xf7) { - return Kind.SHORT_LIST; - } else { - return Kind.LONG_LIST; - } - } - - public boolean isList() { - switch (this) { - case SHORT_LIST: - case LONG_LIST: - return true; - default: - return false; - } - } - } - - /** Read from the provided offset a size of the provided length, assuming this is enough bytes. */ - static int extractSize(final IntUnaryOperator getter, final int offset, final int sizeLength) { - int res = 0; - int shift = 0; - for (int i = 0; i < sizeLength; i++) { - res |= (getter.applyAsInt(offset + (sizeLength - 1) - i) & 0xFF) << shift; - shift += 8; - } - return res; - } - - /** Read from the provided offset a size of the provided length, assuming this is enough bytes. */ - static int extractSizeFromLongItem( - final LongUnaryOperator getter, final long offset, final int sizeLength) { - String oversizedErrorMessage = - "RLP item at offset " - + offset - + " with size value consuming " - + sizeLength - + " bytes exceeds max supported size of " - + Integer.MAX_VALUE; - if (sizeLength > 4) { - throw new RLPException(oversizedErrorMessage); - } - - long res = 0; - int shift = 0; - for (int i = 0; i < sizeLength; i++) { - res |= (getter.applyAsLong(offset + (sizeLength - 1) - i) & 0xFF) << shift; - shift += 8; - } - try { - return Math.toIntExact(res); - } catch (final ArithmeticException e) { - throw new RLPException(oversizedErrorMessage, e); - } - } - - public static RLPElementMetadata rlpElementMetadata( - final LongUnaryOperator byteGetter, final long size, final long elementStart) { - final int prefix = Math.toIntExact(byteGetter.applyAsLong(elementStart)) & 0xFF; - final Kind kind = Kind.of(prefix); - long payloadStart = 0; - int payloadSize = 0; - - switch (kind) { - case BYTE_ELEMENT: - payloadStart = elementStart; - payloadSize = 1; - break; - case SHORT_ELEMENT: - payloadStart = elementStart + 1; - payloadSize = prefix - 0x80; - break; - case LONG_ELEMENT: - final int sizeLengthElt = prefix - 0xb7; - payloadStart = elementStart + 1 + sizeLengthElt; - payloadSize = readLongSize(byteGetter, size, elementStart, sizeLengthElt); - break; - case SHORT_LIST: - payloadStart = elementStart + 1; - payloadSize = prefix - 0xc0; - break; - case LONG_LIST: - final int sizeLengthList = prefix - 0xf7; - payloadStart = elementStart + 1 + sizeLengthList; - payloadSize = readLongSize(byteGetter, size, elementStart, sizeLengthList); - break; - } - - return new RLPElementMetadata(kind, elementStart, payloadStart, payloadSize); - } - - /** The size of the item payload for a "long" item, given the length in bytes of the said size. */ - private static int readLongSize( - final LongUnaryOperator byteGetter, - final long sizeOfRlpEncodedByteString, - final long item, - final int sizeLength) { - // We will read sizeLength bytes from item + 1. There must be enough bytes for this or the input - // is corrupted. - if (sizeOfRlpEncodedByteString - (item + 1) < sizeLength) { - throw new CorruptedRLPInputException( - String.format( - "Invalid RLP item: value of size %d has not enough bytes to read the %d " - + "bytes payload size", - sizeOfRlpEncodedByteString, sizeLength)); - } - - // That size (which is at least 1 byte by construction) shouldn't have leading zeros. - if (byteGetter.applyAsLong(item + 1) == 0) { - throw new MalformedRLPInputException("Malformed RLP item: size of payload has leading zeros"); - } - - final int res = RLPDecodingHelpers.extractSizeFromLongItem(byteGetter, item + 1, sizeLength); - - // We should not have had the size written separately if it was less than 56 bytes long. - if (res < 56) { - throw new MalformedRLPInputException( - String.format("Malformed RLP item: written as a long item, but size %d < 56 bytes", res)); - } - - return res; - } - - public static class RLPElementMetadata { - public final Kind kind; // The type of rlp element - public final long elementStart; // The index at which this element starts - public final long payloadStart; // The index at which the payload of this element starts - public final int payloadSize; // The size of the paylod - - RLPElementMetadata( - final Kind kind, final long elementStart, final long payloadStart, final int payloadSize) { - this.kind = kind; - this.elementStart = elementStart; - this.payloadStart = payloadStart; - this.payloadSize = payloadSize; - } - - /** @return the size of the byte string holding the rlp-encoded value and metadata */ - int getEncodedSize() { - long encodedSize = elementEnd() - elementStart + 1; - try { - return Math.toIntExact(encodedSize); - } catch (ArithmeticException e) { - String errorMessage = - String.format( - "RLP item exceeds max supported size of %d: %d", Integer.MAX_VALUE, encodedSize); - throw new RLPException(errorMessage, e); - } - } - - /** - * The index of the last byte of the rlp encoded element at startIndex - * - * @return - */ - long elementEnd() { - return payloadStart + payloadSize - 1; - } - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPEncodingHelpers.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPEncodingHelpers.java deleted file mode 100644 index 16e808e6..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPEncodingHelpers.java +++ /dev/null @@ -1,110 +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.utils.discoveryutils.bytes; - -class RLPEncodingHelpers { - private RLPEncodingHelpers() {} - - static boolean isSingleRLPByte(final BytesValue value) { - return value.size() == 1 && value.get(0) >= 0; - } - - static boolean isShortElement(final BytesValue value) { - return value.size() <= 55; - } - - static boolean isShortList(final int payloadSize) { - return payloadSize <= 55; - } - - /** The encoded size of the provided value. */ - static int elementSize(final BytesValue value) { - if (isSingleRLPByte(value)) return 1; - - if (isShortElement(value)) return 1 + value.size(); - - return 1 + sizeLength(value.size()) + value.size(); - } - - /** The encoded size of a list given the encoded size of its payload. */ - static int listSize(final int payloadSize) { - int size = 1 + payloadSize; - if (!isShortList(payloadSize)) size += sizeLength(payloadSize); - return size; - } - - /** - * Writes the result of encoding the provided value to the provided destination (which must be big - * enough). - */ - static int writeElement( - final BytesValue value, final MutableBytesValue dest, final int destOffset) { - final int size = value.size(); - if (isSingleRLPByte(value)) { - dest.set(destOffset, value.get(0)); - return destOffset + 1; - } - - if (isShortElement(value)) { - dest.set(destOffset, (byte) (0x80 + size)); - value.copyTo(dest, destOffset + 1); - return destOffset + 1 + size; - } - - final int offset = writeLongMetadata(0xb7, size, dest, destOffset); - value.copyTo(dest, offset); - return offset + size; - } - - /** - * Writes the encoded header of a list provided its encoded payload size to the provided - * destination (which must be big enough). - */ - static int writeListHeader( - final int payloadSize, final MutableBytesValue dest, final int destOffset) { - if (isShortList(payloadSize)) { - dest.set(destOffset, (byte) (0xc0 + payloadSize)); - return destOffset + 1; - } - - return writeLongMetadata(0xf7, payloadSize, dest, destOffset); - } - - private static int writeLongMetadata( - final int baseCode, final int size, final MutableBytesValue dest, final int destOffset) { - final int sizeLength = sizeLength(size); - dest.set(destOffset, (byte) (baseCode + sizeLength)); - int shift = 0; - for (int i = 0; i < sizeLength; i++) { - dest.set(destOffset + sizeLength - i, (byte) (size >> shift)); - shift += 8; - } - return destOffset + 1 + sizeLength; - } - - private static int sizeLength(final int size) { - final int zeros = Integer.numberOfLeadingZeros(size); - return 4 - (zeros / 8); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPOutput.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPOutput.java deleted file mode 100644 index 76ccc389..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/RLPOutput.java +++ /dev/null @@ -1,217 +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.utils.discoveryutils.bytes; - -import io.xdag.utils.discoveryutils.bytes.uint.UInt256Value; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.util.Collection; -import java.util.function.BiConsumer; - -import static com.google.common.base.Preconditions.checkArgument; - -public interface RLPOutput { - - /** Starts a new list. */ - void startList(); - - /** - * Ends the current list. - * - * @throws IllegalStateException if no list has been previously started with {@link #startList()} - * (or any started had already be ended). - */ - void endList(); - - /** - * Writes a new value. - * - * @param v The value to write. - */ - void writeBytesValue(BytesValue v); - - /** - * Writes a RLP "null", that is an empty value. - * - *

This is a shortcut for {@code writeBytesValue(BytesValue.EMPTY)}. - */ - default void writeNull() { - writeBytesValue(BytesValue.EMPTY); - } - - /** - * Writes a scalar (encoded with no leading zeroes). - * - * @param v The scalar to write. - * @throws IllegalArgumentException if {@code v < 0}. - */ - default void writeIntScalar(final int v) { - writeLongScalar(v); - } - - /** - * Writes a scalar (encoded with no leading zeroes). - * - * @param v The scalar to write. - * @throws IllegalArgumentException if {@code v < 0}. - */ - default void writeLongScalar(final long v) { - checkArgument(v >= 0, "Invalid negative value %s for scalar encoding", v); - writeBytesValue(BytesValues.toMinimalBytes(v)); - } - - /** - * Writes a scalar (encoded with no leading zeroes). - * - * @param v The scalar to write. - * @throws IllegalArgumentException if {@code v} is a negative integer ({@code v.signum() < 0}). - */ - default void writeBigIntegerScalar(final BigInteger v) { - checkArgument(v.signum() >= 0, "Invalid negative integer %s for scalar encoding", v); - - final byte[] bytes = v.toByteArray(); - // BigInteger will not include leading zeros by contract, but it always include at least one - // bit of sign (a zero here since it's positive). What that mean is that if the first 1 of the - // resulting number is exactly on a byte boundary, then the sign bit constraint will make the - // value include one extra byte, which will be zero. In other words, they can be one zero bytes - // in practice we should ignore, but there should never be more than one. - writeBytesValue( - bytes.length > 1 && bytes[0] == 0 - ? BytesValue.wrap(bytes, 1, bytes.length - 1) - : BytesValue.wrap(bytes)); - } - - /** - * Writes a scalar (encoded with no leading zeroes). - * - * @param v The scalar to write. - */ - default void writeUInt256Scalar(final UInt256Value v) { - writeBytesValue(BytesValues.trimLeadingZeros(v.getBytes())); - } - - /** - * Writes a single byte value. - * - * @param b The byte to write. - */ - default void writeByte(final byte b) { - writeBytesValue(BytesValue.of(b)); - } - - /** - * Writes a 2-bytes value. - * - *

Note that this is not a "scalar" write: the value will be encoded with exactly 2 bytes. - * - * @param s The 2-bytes short to write. - */ - default void writeShort(final short s) { - final byte[] res = new byte[2]; - res[0] = (byte) (s >> 8); - res[1] = (byte) s; - writeBytesValue(BytesValue.wrap(res)); - } - - /** - * Writes a 4-bytes value. - * - *

Note that this is not a "scalar" write: the value will be encoded with exactly 4 bytes. - * - * @param i The 4-bytes int to write. - */ - default void writeInt(final int i) { - final MutableBytesValue v = MutableBytesValue.create(4); - v.setInt(0, i); - writeBytesValue(v); - } - - /** - * Writes a 8-bytes value. - * - *

Note that this is not a "scalar" write: the value will be encoded with exactly 8 bytes. - * - * @param l The 8-bytes long to write. - */ - default void writeLong(final long l) { - final MutableBytesValue v = MutableBytesValue.create(8); - v.setLong(0, l); - writeBytesValue(v); - } - - /** - * Writes a single byte value. - * - * @param b A value that must fit an unsigned byte. - * @throws IllegalArgumentException if {@code b} does not fit an unsigned byte, that is if either - * {@code b < 0} or {@code b > 0xFF}. - */ - default void writeUnsignedByte(final int b) { - writeBytesValue(BytesValues.ofUnsignedByte(b)); - } - - /** - * Writes a 2-bytes value. - * - * @param s A value that must fit an unsigned 2-bytes short. - * @throws IllegalArgumentException if {@code s} does not fit an unsigned 2-bytes short, that is - * if either {@code s < 0} or {@code s > 0xFFFF}. - */ - default void writeUnsignedShort(final int s) { - writeBytesValue(BytesValues.ofUnsignedShort(s)); - } - - /** - * Writes a 4-bytes value. - * - * @param i A value that must fit an unsigned 4-bytes integer. - * @throws IllegalArgumentException if {@code i} does not fit an unsigned 4-bytes int, that is if - * either {@code i < 0} or {@code i > 0xFFFFFFFFL}. - */ - default void writeUnsignedInt(final long i) { - writeBytesValue(BytesValues.ofUnsignedInt(i)); - } - - /** - * Writes the byte representation of an inet address (so either 4 or 16 bytes long). - * - * @param address The address to write. - */ - default void writeInetAddress(final InetAddress address) { - writeBytesValue(BytesValue.wrap(address.getAddress())); - } - - - default void writeList( - final Collection values, final BiConsumer valueWriter) { - startList(); - for (final T v : values) { - valueWriter.accept(v, this); - } - endList(); - } - - -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/WrappingBytes32.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/WrappingBytes32.java deleted file mode 100644 index c8a34e40..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/WrappingBytes32.java +++ /dev/null @@ -1,69 +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.utils.discoveryutils.bytes; - -import static com.google.common.base.Preconditions.checkArgument; - -public class WrappingBytes32 extends AbstractBytesValue implements Bytes32 { - - private final BytesValue value; - - public WrappingBytes32(final BytesValue value) { - checkArgument( - value.size() == SIZE, "Expected value to be %s bytes, but is %s bytes", SIZE, value.size()); - this.value = value; - } - - @Override - public byte get(final int i) { - return value.get(i); - } - - @Override - public BytesValue slice(final int index, final int length) { - return value.slice(index, length); - } - - @Override - public MutableBytes32 mutableCopy() { - final MutableBytes32 copy = MutableBytes32.create(); - value.copyTo(copy); - return copy; - } - - @Override - public Bytes32 copy() { - return mutableCopy(); - } - - @Override - public byte[] getArrayUnsafe() { - return value.getArrayUnsafe(); - } - - @Override - public int size() { - return value.size(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractRLPInput.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractRLPInput.java deleted file mode 100644 index 3d7b5cd0..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractRLPInput.java +++ /dev/null @@ -1,480 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.MalformedRLPInputException; -import io.xdag.utils.discoveryutils.RLPInput; -import io.xdag.utils.discoveryutils.bytes.*; -import io.xdag.utils.discoveryutils.bytes.RLPDecodingHelpers.Kind; - -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.Arrays; - -import static com.google.common.base.Preconditions.checkState; - - -abstract class AbstractRLPInput implements RLPInput { - - private final boolean lenient; - - protected long size; // The number of bytes in this rlp-encoded byte string - - // Information on the item the input currently is at (next thing to read). - protected long - currentItem; // Offset in value to the beginning of the item (or value.size() if done) - Kind currentKind; // Kind of the item. - long currentPayloadOffset; // Offset to the beginning of the current item payload. - int currentPayloadSize; // Size of the current item payload. - - // Information regarding opened list. The depth is how many list deep we are, and endOfListOffset - // holds the offset in value at which each list ends (indexed by depth). Allows to know if we're - // at the end of our current list, and if there is any unfinished one. - private int depth; - private long[] endOfListOffset = new long[4]; - - AbstractRLPInput(final boolean lenient) { - this.lenient = lenient; - } - - protected void init(final long inputSize, final boolean shouldFitInputSizeExactly) { - if (inputSize == 0) { - return; - } - - currentItem = 0; - // Initially set the size to the input as prepareCurrentItem() needs it. Once we've prepared the - // top level item, we know where that item ends exactly and can update the size to that more - // precise value (which basically mean we'll throw errors on malformed inputs potentially - // sooner). - size = inputSize; - prepareCurrentItem(); - if (currentKind.isList()) { - size = nextItem(); - } - - // No matter what, if the first item advertise a payload ending after the end of the input, that - // input is corrupted. - if (size > inputSize) { - // Our error message include a snippet of the input and that code assume size is not set - // outside of the input, and that's exactly the case we're testing, so resetting the size - // simply for the sake of the error being properly generated. - final long itemEnd = size; - size = inputSize; - throw corrupted( - "Input doesn't have enough data for RLP encoding: encoding advertise a " - + "payload ending at byte %d but input has size %d", - itemEnd, inputSize); - } - - if (shouldFitInputSizeExactly && inputSize > size) { - throwMalformed( - "Input has extra data after RLP encoding: encoding ends at byte %d but " - + "input has size %d", - size, inputSize); - } - - validateCurrentItem(); - } - - protected abstract byte inputByte(long offset); - - protected abstract BytesValue inputSlice(long offset, int length); - - protected abstract Bytes32 inputSlice32(long offset); - - protected abstract String inputHex(long offset, int length); - - protected abstract BigInteger getUnsignedBigInteger(long offset, int length); - - protected abstract int getInt(long offset); - - protected abstract long getLong(long offset); - - /** - * Sets the input to the item provided (an offset to the beginning of an item) and check this is - * valid. - * - * @param item the value to which the current item is to be set. - */ - protected void setTo(final long item) { - currentItem = item; - if (currentItem >= size) { - // Setting somewhat safe values so that multiple calls to setTo(nextItem()) don't do anything - // even when at the end. - currentKind = null; - currentPayloadOffset = item; - currentPayloadSize = 0; - return; - } - prepareCurrentItem(); - validateCurrentItem(); - } - - private void prepareCurrentItem() { - // Sets the kind of the item, the offset at which his payload starts and the size of this - // payload. - try { - RLPDecodingHelpers.RLPElementMetadata elementMetadata = - RLPDecodingHelpers.rlpElementMetadata(this::inputByte, size, currentItem); - currentKind = elementMetadata.kind; - currentPayloadOffset = elementMetadata.payloadStart; - currentPayloadSize = elementMetadata.payloadSize; - } catch (RLPException exception) { - String message = - String.format( - exception.getMessage() + getErrorMessageSuffix(), getErrorMessageSuffixParams()); - throw new RLPException(message, exception); - } - } - - private void validateCurrentItem() { - if (currentKind == Kind.SHORT_ELEMENT) { - // Validate that a single byte SHORT_ELEMENT payload is not <= 0x7F. If it is, is should have - // been written as a BYTE_ELEMENT. - if (currentPayloadSize == 1 - && currentPayloadOffset < size - && (payloadByte(0) & 0xFF) <= 0x7F) { - throwMalformed( - "Malformed RLP item: single byte value 0x%s should have been " - + "written without a prefix", - hex(currentPayloadOffset, currentPayloadOffset + 1)); - } - } - - if (currentPayloadSize > 0 && currentPayloadOffset >= size) { - throw corrupted( - "Invalid RLP item: payload should start at offset %d but input has only " + "%d bytes", - currentPayloadOffset, size); - } - if (size - currentPayloadOffset < currentPayloadSize) { - throw corrupted( - "Invalid RLP item: payload starting at byte %d should be %d bytes long, but input " - + "has only %d bytes from that offset", - currentPayloadOffset, currentPayloadSize, size - currentPayloadOffset); - } - } - - private long nextItem() { - return currentPayloadOffset + currentPayloadSize; - } - - @Override - public boolean isDone() { - // The input is done if we're out of input, but also if we've called leaveList() an appropriate - // amount of times. - return currentItem >= size && depth == 0; - } - - private String hex(final long start, final long taintedEnd) { - final long end = Math.min(taintedEnd, size); - final long size = end - start; - if (size < 10) { - return inputHex(start, Math.toIntExact(size)); - } else { - return String.format("%s...%s", inputHex(start, 4), inputHex(end - 4, 4)); - } - } - - private void throwMalformed(final String msg, final Object... params) { - if (!lenient) throw new MalformedRLPInputException(errorMsg(msg, params)); - } - - private CorruptedRLPInputException corrupted(final String msg, final Object... params) { - throw new CorruptedRLPInputException(errorMsg(msg, params)); - } - - private RLPException error(final String msg, final Object... params) { - throw new RLPException(errorMsg(msg, params)); - } - - private RLPException error(final Throwable cause, final String msg, final Object... params) { - throw new RLPException(errorMsg(msg, params), cause); - } - - private String errorMsg(final String message, final Object... params) { - return String.format( - message + getErrorMessageSuffix(), concatParams(params, getErrorMessageSuffixParams())); - } - - private String getErrorMessageSuffix() { - return " (at bytes %d-%d: %s%s[%s]%s%s)"; - } - - private Object[] getErrorMessageSuffixParams() { - final long start = currentItem; - final long end = Math.min(size, nextItem()); - final long realStart = Math.max(0, start - 4); - final long realEnd = Math.min(size, end + 4); - return new Object[] { - start, - end, - realStart == 0 ? "" : "...", - hex(realStart, start), - hex(start, end), - hex(end, realEnd), - realEnd == size ? "" : "..." - }; - } - - private static Object[] concatParams(final Object[] initial, final Object... others) { - final Object[] params = Arrays.copyOf(initial, initial.length + others.length); - System.arraycopy(others, 0, params, initial.length, others.length); - return params; - } - - private void checkElt(final String what) { - if (currentItem >= size) { - throw error("Cannot read a %s, input is fully consumed", what); - } - if (isEndOfCurrentList()) { - throw error("Cannot read a %s, reached end of current list", what); - } - if (currentKind.isList()) { - throw error("Cannot read a %s, current item is a list", what); - } - } - - private void checkElt(final String what, final int expectedSize) { - checkElt(what); - if (currentPayloadSize != expectedSize) - throw error( - "Cannot read a %s, expecting %d bytes but current element is %d bytes long", - what, expectedSize, currentPayloadSize); - } - - private void checkScalar(final String what) { - checkElt(what); - if (currentPayloadSize > 0 && payloadByte(0) == 0) { - throwMalformed("Invalid scalar, has leading zeros bytes"); - } - } - - private void checkScalar(final String what, final int maxExpectedSize) { - checkScalar(what); - if (currentPayloadSize > maxExpectedSize) - throw error( - "Cannot read a %s, expecting a maximum of %d bytes but current element is %d bytes long", - what, maxExpectedSize, currentPayloadSize); - } - - private byte payloadByte(final int offsetInPayload) { - return inputByte(currentPayloadOffset + offsetInPayload); - } - - private BytesValue payloadSlice() { - return inputSlice(currentPayloadOffset, currentPayloadSize); - } - - @Override - public void skipNext() { - setTo(nextItem()); - } - - @Override - public long readLongScalar() { - checkScalar("long scalar", 8); - long res = 0; - int shift = 0; - for (int i = 0; i < currentPayloadSize; i++) { - res |= ((long) payloadByte(currentPayloadSize - i - 1) & 0xFF) << shift; - shift += 8; - } - if (res < 0) { - error("long scalar %s is not non-negative", res); - } - setTo(nextItem()); - return res; - } - - - public int readIntScalar() { - checkScalar("int scalar", 4); - int res = 0; - int shift = 0; - for (int i = 0; i < currentPayloadSize; i++) { - res |= (payloadByte(currentPayloadSize - i - 1) & 0xFF) << shift; - shift += 8; - } - setTo(nextItem()); - return res; - } - - @Override - public BigInteger readBigIntegerScalar() { - checkScalar("arbitrary precision scalar"); - final BigInteger res = getUnsignedBigInteger(currentPayloadOffset, currentPayloadSize); - setTo(nextItem()); - return res; - } - - private Bytes32 readBytes32Scalar() { - checkScalar("32-bytes scalar", 32); - final MutableBytes32 res = MutableBytes32.create(); - payloadSlice().copyTo(res, res.size() - currentPayloadSize); - setTo(nextItem()); - return res; - } - - - - - - @Override - public short readShort() { - checkElt("2-byte short", 2); - final short s = (short) ((payloadByte(0) << 8) | (payloadByte(1) & 0xFF)); - setTo(nextItem()); - return s; - } - - - - - @Override - public InetAddress readInetAddress() { - checkElt("inet address"); - if (currentPayloadSize != 4 && currentPayloadSize != 16) { - throw error( - "Cannot read an inet address, current element is %d bytes long", currentPayloadSize); - } - final byte[] address = new byte[currentPayloadSize]; - for (int i = 0; i < currentPayloadSize; i++) { - address[i] = payloadByte(i); - } - setTo(nextItem()); - try { - return InetAddress.getByAddress(address); - } catch (final UnknownHostException e) { - // InetAddress.getByAddress() only throws for an address of illegal length, and we have - // validated that length already, this this genuinely shouldn't throw. - throw new AssertionError(e); - } - } - - @Override - public BytesValue readBytesValue() { - checkElt("arbitrary bytes value"); - final BytesValue res = payloadSlice(); - setTo(nextItem()); - return res; - } - - - - - - @Override - public int enterList() { - return enterList(false); - } - - /** - * Enters the list, but does not return the number of item of the entered list. This prevents - * bouncing all around the file to read values that are probably not even used. - * - * @see #enterList() - * @param skipCount true if the element count is not required. - * @return -1 if skipCount==true, otherwise, the number of item of the entered list. - */ - public int enterList(final boolean skipCount) { - if (currentItem >= size) { - throw error("Cannot enter a lists, input is fully consumed"); - } - if (!currentKind.isList()) { - throw error("Expected current item to be a list, but it is: " + currentKind); - } - - ++depth; - if (depth > endOfListOffset.length) { - endOfListOffset = Arrays.copyOf(endOfListOffset, (endOfListOffset.length * 3) / 2); - } - // The first list element is the beginning of the payload. It's end is the end of this item. - final long listStart = currentPayloadOffset; - final long listEnd = nextItem(); - - if (listEnd > size) { - throw corrupted( - "Invalid RLP item: list payload should end at offset %d but input has only %d bytes", - listEnd, size); - } - - endOfListOffset[depth - 1] = listEnd; - int count = -1; - - if (!skipCount) { - // Count list elements from first one. - count = 0; - setTo(listStart); - while (currentItem < listEnd) { - ++count; - setTo(nextItem()); - } - } - - // And lastly reset on the list first element before returning - setTo(listStart); - return count; - } - - @Override - public void leaveList() { - leaveList(false); - } - - @Override - public void leaveList(final boolean ignoreRest) { - checkState(depth > 0, "Not within an RLP list"); - - if (!ignoreRest) { - final long listEndOffset = endOfListOffset[depth - 1]; - if (currentItem < listEndOffset) throw error("Not at the end of the current list"); - } - - --depth; - } - - @Override - public boolean nextIsList() { - return currentKind != null && currentKind.isList(); - } - - @Override - public boolean nextIsNull() { - return currentKind == Kind.SHORT_ELEMENT && currentPayloadSize == 0; - } - - - - @Override - public boolean isEndOfCurrentList() { - return depth > 0 && currentItem >= endOfListOffset[depth - 1]; - } - - @Override - public void reset() { - setTo(0); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractUInt256Value.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractUInt256Value.java deleted file mode 100644 index bf671dec..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/AbstractUInt256Value.java +++ /dev/null @@ -1,196 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.AbstractBytes32Backed; -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.Bytes32s; - -import java.util.function.Supplier; - -import static com.google.common.base.Preconditions.checkArgument; - -abstract class AbstractUInt256Value> extends AbstractBytes32Backed - implements UInt256Value { - - private final Supplier> mutableCtor; - - protected AbstractUInt256Value(final Bytes32 bytes, final Supplier> mutableCtor) { - super(bytes); - this.mutableCtor = mutableCtor; - } - - private T unaryOp(final UInt256Bytes.UnaryOp op) { - final Counter result = mutableCtor.get(); - op.applyOp(getBytes(), result.getBytes()); - return result.get(); - } - - protected T binaryOp(final UInt256Value value, final UInt256Bytes.BinaryOp op) { - final Counter result = mutableCtor.get(); - op.applyOp(getBytes(), value.getBytes(), result.getBytes()); - return result.get(); - } - - private T binaryLongOp(final long value, final UInt256Bytes.BinaryLongOp op) { - final Counter result = mutableCtor.get(); - op.applyOp(getBytes(), value, result.getBytes()); - return result.get(); - } - - private T ternaryOp( - final UInt256Value v1, final UInt256Value v2, final UInt256Bytes.TernaryOp op) { - final Counter result = mutableCtor.get(); - op.applyOp(getBytes(), v1.getBytes(), v2.getBytes(), result.getBytes()); - return result.get(); - } - - @Override - public T copy() { - final Counter result = mutableCtor.get(); - getBytes().copyTo(result.getBytes()); - return result.get(); - } - - @Override - public T plus(final T value) { - return binaryOp(value, UInt256Bytes::add); - } - - @Override - public T plus(final long value) { - checkArgument(value >= 0, "Invalid negative value %s", value); - return binaryLongOp(value, UInt256Bytes::add); - } - - @Override - public T plusModulo(final T value, final UInt256 modulo) { - return ternaryOp(value, modulo, UInt256Bytes::addModulo); - } - - @Override - public T minus(final T value) { - return binaryOp(value, UInt256Bytes::subtract); - } - - @Override - public T minus(final long value) { - checkArgument(value >= 0, "Invalid negative value %s", value); - return binaryLongOp(value, UInt256Bytes::subtract); - } - - @Override - public T times(final T value) { - return binaryOp(value, UInt256Bytes::multiply); - } - - @Override - public T times(final long value) { - checkArgument(value >= 0, "Invalid negative value %s", value); - return binaryLongOp(value, UInt256Bytes::multiply); - } - - @Override - public T timesModulo(final T value, final UInt256 modulo) { - return ternaryOp(value, modulo, UInt256Bytes::multiplyModulo); - } - - @Override - public T dividedBy(final T value) { - return binaryOp(value, UInt256Bytes::divide); - } - - @Override - public T dividedBy(final long value) { - checkArgument(value >= 0, "Invalid negative value %s", value); - return binaryLongOp(value, UInt256Bytes::divide); - } - - @Override - public T pow(final T value) { - return binaryOp(value, UInt256Bytes::exponent); - } - - @Override - public T mod(final T value) { - return binaryOp(value, UInt256Bytes::modulo); - } - - @Override - public T mod(final long value) { - checkArgument(value >= 0, "Invalid negative value %s", value); - return binaryLongOp(value, UInt256Bytes::modulo); - } - - @Override - public Int256 signExtent(final UInt256 value) { - return new DefaultInt256(binaryOp(value, UInt256Bytes::signExtend).getBytes()); - } - - @Override - public T and(final T value) { - return binaryOp(value, Bytes32s::and); - } - - @Override - public T or(final T value) { - return binaryOp(value, Bytes32s::or); - } - - @Override - public T xor(final T value) { - return binaryOp(value, Bytes32s::xor); - } - - @Override - public T not() { - return unaryOp(Bytes32s::not); - } - - @Override - public int compareTo(final T other) { - return UInt256Bytes.compareUnsigned(getBytes(), other.getBytes()); - } - - @Override - public boolean equals(final Object other) { - if (other == null) return false; - // Note that we do want strictly class equality in this case: we don't want 2 quantity of - // mismatching unit to be considered equal, even if they do represent the same number. - if (this.getClass() != other.getClass()) return false; - - final UInt256Value that = (UInt256Value) other; - return this.getBytes().equals(that.getBytes()); - } - - @Override - public int hashCode() { - return bytes.hashCode(); - } - - @Override - public String toString() { - return UInt256Bytes.toString(getBytes()); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BaseUInt256Value.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BaseUInt256Value.java deleted file mode 100644 index 0a5abd25..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BaseUInt256Value.java +++ /dev/null @@ -1,69 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; - -import java.math.BigInteger; -import java.util.function.Supplier; - -import static com.google.common.base.Preconditions.checkArgument; - -public abstract class BaseUInt256Value> extends AbstractUInt256Value { - - protected BaseUInt256Value(final Bytes32 bytes, final Supplier> mutableCtor) { - super(bytes, mutableCtor); - } - - protected BaseUInt256Value(final long v, final Supplier> mutableCtor) { - this(UInt256Bytes.of(v), mutableCtor); - checkArgument(v >= 0, "Invalid negative value %s for an unsigned scalar", v); - } - - protected BaseUInt256Value(final BigInteger v, final Supplier> mutableCtor) { - this(UInt256Bytes.of(v), mutableCtor); - checkArgument(v.signum() >= 0, "Invalid negative value %s for an unsigned scalar", v); - } - - protected BaseUInt256Value(final String hexString, final Supplier> mutableCtor) { - this(Bytes32.fromHexStringLenient(hexString), mutableCtor); - } - - public T times(final UInt256 value) { - return binaryOp(value, UInt256Bytes::multiply); - } - - public T mod(final UInt256 value) { - return binaryOp(value, UInt256Bytes::modulo); - } - - public int compareTo(final UInt256 other) { - return UInt256Bytes.compareUnsigned(this.bytes, other.getBytes()); - } - - @Override - public UInt256 asUInt256() { - return new DefaultUInt256(bytes); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BytesValueRLPInput.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BytesValueRLPInput.java deleted file mode 100644 index e5b821d6..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/BytesValueRLPInput.java +++ /dev/null @@ -1,87 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.BytesValues; - -import java.math.BigInteger; - -public class BytesValueRLPInput extends AbstractRLPInput { - - // The RLP encoded data. - private final BytesValue value; - - public BytesValueRLPInput(final BytesValue value, final boolean lenient) { - this(value, lenient, true); - } - - public BytesValueRLPInput( - final BytesValue value, final boolean lenient, final boolean shouldFitExactly) { - super(lenient); - this.value = value; - init(value.size(), shouldFitExactly); - } - - @Override - protected byte inputByte(final long offset) { - return value.get(offset); - } - - @Override - protected BytesValue inputSlice(final long offset, final int length) { - return value.slice(Math.toIntExact(offset), length); - } - - @Override - protected Bytes32 inputSlice32(final long offset) { - return Bytes32.wrap(value, Math.toIntExact(offset)); - } - - @Override - protected String inputHex(final long offset, final int length) { - return value.slice(Math.toIntExact(offset), length).toString().substring(2); - } - - @Override - protected BigInteger getUnsignedBigInteger(final long offset, final int length) { - return BytesValues.asUnsignedBigInteger(value.slice(Math.toIntExact(offset), length)); - } - - @Override - protected int getInt(final long offset) { - return value.getInt(Math.toIntExact(offset)); - } - - @Override - protected long getLong(final long offset) { - return value.getLong(Math.toIntExact(offset)); - } - - @Override - public BytesValue raw() { - return value; - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/CorruptedRLPInputException.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/CorruptedRLPInputException.java deleted file mode 100644 index 40a950d5..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/CorruptedRLPInputException.java +++ /dev/null @@ -1,31 +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.utils.discoveryutils.bytes.uint; - -public class CorruptedRLPInputException extends RLPException { - public CorruptedRLPInputException(final String message) { - super(message); - } -} - diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Counter.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Counter.java deleted file mode 100644 index 31465197..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Counter.java +++ /dev/null @@ -1,97 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.MutableBytes32; - -import java.util.function.Function; - -import static com.google.common.base.Preconditions.checkArgument; - -public class Counter> { - - private final MutableBytes32 bytes; - private final T value; - - // Kept around for copy() - private final Function wrapFct; - - protected Counter(final Function wrapFct) { - this(MutableBytes32.create(), wrapFct); - } - - protected Counter(final MutableBytes32 bytes, final Function wrapFct) { - this.bytes = bytes; - this.value = wrapFct.apply(bytes); - this.wrapFct = wrapFct; - } - - public T get() { - return value; - } - - public MutableBytes32 getBytes() { - return bytes; - } - - public Counter copy() { - return new Counter<>(bytes.mutableCopy(), wrapFct); - } - - public void increment() { - increment(1); - } - - public void increment(final long increment) { - checkArgument(increment >= 0, "Invalid negative increment %s", increment); - UInt256Bytes.add(bytes, increment, bytes); - } - - public void increment(final T increment) { - UInt256Bytes.add(bytes, increment.getBytes(), bytes); - } - - public void decrement() { - decrement(1); - } - - public void decrement(final long decrement) { - checkArgument(decrement >= 0, "Invalid negative decrement %s", decrement); - UInt256Bytes.subtract(bytes, decrement, bytes); - } - - public void decrement(final T decrement) { - UInt256Bytes.subtract(bytes, decrement.getBytes(), bytes); - } - - public void set(final T value) { - value.getBytes().copyTo(bytes); - } - - @Override - public String toString() { - return value.toString(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultInt256.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultInt256.java deleted file mode 100644 index e4616ef7..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultInt256.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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.AbstractBytes32Backed; -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.MutableBytes32; - -import static com.google.common.base.Preconditions.checkArgument; - -class DefaultInt256 extends AbstractBytes32Backed implements Int256 { - - DefaultInt256(final Bytes32 bytes) { - super(bytes); - checkArgument( - bytes.size() == SIZE, - "Invalid value for a UInt256: expecting %s bytes but got %s", - SIZE, - bytes.size()); - } - - // Note meant to be used directly, use Int256.MINUS_ONE instead - static DefaultInt256 minusOne() { - final MutableBytes32 v = MutableBytes32.create(); - v.fill((byte) 0xFF); - return new DefaultInt256(v); - } - - private Int256 binaryOp(final Int256 value, final UInt256Bytes.BinaryOp op) { - final MutableBytes32 result = MutableBytes32.create(); - op.applyOp(getBytes(), value.getBytes(), result); - return new DefaultInt256(result); - } - - @Override - public Int256 dividedBy(final Int256 value) { - return binaryOp(value, Int256Bytes::divide); - } - - @Override - public Int256 mod(final Int256 value) { - return binaryOp(value, Int256Bytes::mod); - } - - @Override - public int compareTo(final Int256 other) { - final boolean thisNeg = this.isNegative(); - final boolean otherNeg = other.isNegative(); - - if (thisNeg) { - // We're negative, if the other isn't it is bigger, otherwise both negative => compare same as - // unsigned. - return otherNeg ? UInt256Bytes.compareUnsigned(getBytes(), other.getBytes()) : -1; - } - - // We're positive, if the other isn't we are bigger, otherwise both are positive and we can use - // unsigned comparison. - return otherNeg ? 1 : UInt256Bytes.compareUnsigned(getBytes(), other.getBytes()); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultUInt256.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultUInt256.java deleted file mode 100644 index bbcb4a63..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/DefaultUInt256.java +++ /dev/null @@ -1,49 +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.utils.discoveryutils.bytes.uint; - - -import io.xdag.utils.discoveryutils.bytes.Bytes32; - -class DefaultUInt256 extends AbstractUInt256Value implements UInt256 { - - DefaultUInt256(final Bytes32 bytes) { - super(bytes, UInt256Counter::new); - } - - static Counter newVar() { - return new UInt256Counter(); - } - - @Override - public UInt256 asUInt256() { - return this; - } - - private static class UInt256Counter extends Counter { - private UInt256Counter() { - super(DefaultUInt256::new); - } - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256.java deleted file mode 100644 index c0240b4f..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256.java +++ /dev/null @@ -1,57 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.Bytes32Backed; - -public interface Int256 extends Bytes32Backed, Comparable { - - int SIZE = 32; - - /** The value -1. */ - Int256 MINUS_ONE = DefaultInt256.minusOne(); - - static Int256 wrap(final Bytes32 bytes) { - return new DefaultInt256(bytes); - } - - default boolean isZero() { - return getBytes().isZero(); - } - - /** @return True if the value is negative. */ - default boolean isNegative() { - return getBytes().get(0) < 0; - } - - Int256 dividedBy(Int256 value); - - Int256 mod(Int256 value); - - /** @return A view of the bytes of this number as signed (two's complement). */ - default UInt256 asUnsigned() { - return new DefaultUInt256(getBytes()); - } -} \ No newline at end of file diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256Bytes.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256Bytes.java deleted file mode 100644 index 841bd773..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/Int256Bytes.java +++ /dev/null @@ -1,95 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.BytesValue; -import io.xdag.utils.discoveryutils.bytes.BytesValues; -import io.xdag.utils.discoveryutils.bytes.MutableBytes32; - -import java.math.BigInteger; -import java.util.function.BinaryOperator; - -abstract class Int256Bytes { - - private Int256Bytes() {} - - private static final byte ALL_ZERO_BYTE = (byte) 0x00; - private static final byte ALL_ONE_BYTE = (byte) 0xFF; - - private static void copy(final BigInteger result, final MutableBytes32 destination) { - final byte padding = result.signum() < 0 ? ALL_ONE_BYTE : ALL_ZERO_BYTE; - UInt256Bytes.copyPadded(BytesValue.wrap(result.toByteArray()), destination, padding); - } - - private static void doOnSignedBigInteger( - final Bytes32 v1, - final Bytes32 v2, - final MutableBytes32 dest, - final BinaryOperator operator) { - final BigInteger i1 = BytesValues.asSignedBigInteger(v1); - final BigInteger i2 = BytesValues.asSignedBigInteger(v2); - final BigInteger result = operator.apply(i1, i2); - copy(result, dest); - } - - // Tests if this value represents -2^255, that is the first byte is 1 followed by only 0. Used to - // implement the overflow condition of the Yellow Paper in signedDivide(). - private static boolean isMinusP255(final Bytes32 v) { - if (v.get(0) != (byte) 0x80) return false; - - byte b = 0; - for (int i = 1; i < v.size(); i++) { - b |= v.get(i); - } - return b == 0; - } - - static void divide(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - if (v2.isZero()) { - result.clear(); - } else if (v2.equals(Int256.MINUS_ONE.getBytes()) && isMinusP255(v2)) { - // Set to -2^255. - result.clear(); - result.set(0, (byte) 0x80); - } else { - doOnSignedBigInteger(v1, v2, result, BigInteger::divide); - } - } - - static void mod(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - if (v2.isZero()) { - result.clear(); - } else { - doOnSignedBigInteger( - v1, - v2, - result, - (val, mod) -> { - final BigInteger absModulo = val.abs().mod(mod.abs()); - return val.signum() < 0 ? absModulo.negate() : absModulo; - }); - } - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/RLPException.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/RLPException.java deleted file mode 100644 index b0ff5799..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/RLPException.java +++ /dev/null @@ -1,34 +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.utils.discoveryutils.bytes.uint; - -public class RLPException extends RuntimeException { - public RLPException(final String message) { - this(message, null); - } - - public RLPException(final String message, final Throwable throwable) { - super(message, throwable); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256.java deleted file mode 100644 index 5c19e6bc..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256.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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32; - -import java.math.BigInteger; - -public interface UInt256 extends UInt256Value { - /** The value 0. */ - UInt256 ZERO = of(0); - /** The value 1. */ - UInt256 ONE = of(1); - /** The value 32. */ - UInt256 U_32 = of(32); - - static UInt256 of(final long value) { - return new DefaultUInt256(UInt256Bytes.of(value)); - } - - static UInt256 of(final BigInteger value) { - return new DefaultUInt256(UInt256Bytes.of(value)); - } - - static UInt256 wrap(final Bytes32 value) { - return new DefaultUInt256(value); - } - - static Counter newCounter() { - return DefaultUInt256.newVar(); - } - - static Counter newCounter(final UInt256Value initialValue) { - final Counter c = DefaultUInt256.newVar(); - initialValue.getBytes().copyTo(c.getBytes()); - return c; - } - - static UInt256 fromHexString(final String str) { - return new DefaultUInt256(Bytes32.fromHexStringLenient(str)); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Bytes.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Bytes.java deleted file mode 100644 index f808e1b8..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Bytes.java +++ /dev/null @@ -1,429 +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.utils.discoveryutils.bytes.uint; - -import com.google.common.annotations.VisibleForTesting; -import io.xdag.utils.discoveryutils.bytes.*; - -import java.math.BigInteger; -import java.util.function.BinaryOperator; - -import static com.google.common.base.Preconditions.checkArgument; - -public abstract class UInt256Bytes { - - private UInt256Bytes() {} - - interface UnaryOp { - void applyOp(Bytes32 v, MutableBytes32 result); - } - - interface BinaryOp { - void applyOp(Bytes32 v1, Bytes32 v2, MutableBytes32 result); - } - - interface BinaryLongOp { - void applyOp(Bytes32 v1, long v2, MutableBytes32 result); - } - - interface TernaryOp { - void applyOp(Bytes32 v1, Bytes32 v2, Bytes32 v3, MutableBytes32 result); - } - - private static final int SIZE = Bytes32.SIZE; - - private static final BigInteger P256 = BigInteger.valueOf(2).pow(8 * 32); - - /** The number of ints a word contains. */ - private static final int INT_SIZE = 32 / 4; - - private static final byte ALL_ZERO_BYTE = (byte) 0x00; - private static final byte ALL_ONE_BYTE = (byte) 0xFF; - - private static final UInt256 U_31 = UInt256.of(31); - - /** This mask is used to obtain the value of an int as if it were unsigned. */ - private static final long LONG_MASK = 0xffffffffL; - - static void copyPadded( - final BytesValue toCopy, final MutableBytes32 destination, final byte padByte) { - final int copySize = toCopy.size(); - if (copySize == SIZE) { - toCopy.copyTo(destination); - } else if (copySize > SIZE) { - toCopy.slice(copySize - SIZE, SIZE).copyTo(destination); - } else { - final int padding = SIZE - toCopy.size(); - destination.mutableSlice(0, padding).fill(padByte); - toCopy.copyTo(destination, padding); - } - } - - private static void copy(final BigInteger result, final MutableBytes32 destination) { - copyPadded(BytesValue.wrap(result.toByteArray()), destination, ALL_ZERO_BYTE); - } - - private interface TriOperator { - T apply(T op1, T op2, T op3); - } - - private static void doOnBigInteger( - final Bytes32 v1, - final Bytes32 v2, - final MutableBytes32 dest, - final BinaryOperator operator) { - final BigInteger i1 = BytesValues.asUnsignedBigInteger(v1); - final BigInteger i2 = BytesValues.asUnsignedBigInteger(v2); - final BigInteger result = operator.apply(i1, i2); - copy(result, dest); - } - - private static void doOnBigInteger( - final Bytes32 v1, - final Bytes32 v2, - final Bytes32 v3, - final MutableBytes32 dest, - final TriOperator operator) { - final BigInteger i1 = BytesValues.asUnsignedBigInteger(v1); - final BigInteger i2 = BytesValues.asUnsignedBigInteger(v2); - final BigInteger i3 = BytesValues.asUnsignedBigInteger(v3); - final BigInteger result = operator.apply(i1, i2, i3); - copy(result, dest); - } - - public static void add(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - long carry = 0; - - // Add ints from the right hand side, propagating any carry. - for (int i = INT_SIZE - 1; i >= 0; i--) { - final long sum = (v1.getInt(i * 4) & LONG_MASK) + (v2.getInt(i * 4) & LONG_MASK) + carry; - result.setInt(i * 4, (int) sum); - carry = sum >>> 32; - } - // Discard the final carry since we work modulo 256. - } - - public static void add(final Bytes32 v1, final long v2, final MutableBytes32 result) { - final long sum1 = (v1.getInt(SIZE - 4) & LONG_MASK) + (v2 & LONG_MASK); - result.setInt(SIZE - 4, (int) sum1); - - final long sum2 = (v1.getInt(SIZE - 8) & LONG_MASK) + (v2 >>> 32) + (sum1 >>> 32); - result.setInt(SIZE - 8, (int) sum2); - - long carry = (int) (sum2 >>> 32); - for (int i = INT_SIZE - 3; i >= 0; i--) { - final long sum = (v1.getInt(i * 4) & LONG_MASK) + carry; - result.setInt(i * 4, (int) sum); - carry = sum >>> 32; - } - } - - public static void addModulo( - final Bytes32 v1, final Bytes32 v2, final Bytes32 modulo, final MutableBytes32 result) { - if (modulo.isZero()) { - result.clear(); - } else { - doOnBigInteger(v1, v2, modulo, result, (op1, op2, mod) -> op1.add(op2).mod(mod)); - } - } - - public static void subtract(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - final int sign = compareUnsigned(v1, v2); - - if (sign == 0) { - result.clear(); - return; - } - - final Bytes32 a; - final Bytes32 b; - if (sign > 0) { - a = v1; - b = v2; - } else { - a = v2; - b = v1; - } - - long diff = 0; - - for (int i = INT_SIZE - 1; i >= 0; i--) { - diff = (a.getInt(i * 4) & LONG_MASK) - (b.getInt(i * 4) & LONG_MASK) - ((int) -(diff >> 32)); - result.setInt(i * 4, (int) diff); - } - - if (sign < 0) { - negateSigned(result, result); - } - } - - public static void subtract(final Bytes32 v1, final long v2, final MutableBytes32 result) { - final int sign = fitsLong(v1) ? Long.compare(v1.getLong(SIZE - 8), v2) : 1; - if (sign == 0) { - result.clear(); - return; - } - - if (sign < 0) { - final long diff1 = (v2 & LONG_MASK) - (v1.getInt(SIZE - 4) & LONG_MASK); - result.setInt(SIZE - 4, (int) diff1); - - final long diff2 = (v2 >>> 32) - (v1.getInt(SIZE - 8) & LONG_MASK) - ((int) -(diff1 >> 32)); - result.setInt(SIZE - 8, (int) diff2); - - long diff = diff2; - for (int i = INT_SIZE - 3; i >= 0; i--) { - diff = -(v1.getInt(i * 4) & LONG_MASK) - ((int) -(diff >> 32)); - result.setInt(i * 4, (int) diff); - } - negateSigned(result, result); - } else { - final long diff1 = (v1.getInt(SIZE - 4) & LONG_MASK) - (v2 & LONG_MASK); - result.setInt(SIZE - 4, (int) diff1); - - final long diff2 = (v1.getInt(SIZE - 8) & LONG_MASK) - (v2 >>> 32) - ((int) -(diff1 >> 32)); - result.setInt(SIZE - 8, (int) diff2); - - long diff = diff2; - for (int i = INT_SIZE - 3; i >= 0; i--) { - diff = (v1.getInt(i * 4) & LONG_MASK) - ((int) -(diff >> 32)); - result.setInt(i * 4, (int) diff); - if (diff == 0) break; - } - } - } - - private static void negateSigned(final Bytes32 v, final MutableBytes32 result) { - Bytes32s.not(v, result); - add(result, UInt256.ONE.getBytes(), result); - } - - private static boolean isPowerOf2(final long n) { - return (n ^ (n - 1)) == 0; - } - - public static void multiply(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - doOnBigInteger(v1, v2, result, BigInteger::multiply); - } - - public static void multiply(final Bytes32 v1, final long v2, final MutableBytes32 result) { - if (v2 == 0) { - result.clear(); - } else if (v2 > 0 && isPowerOf2(v2)) { - final int shifts = log2(v2); - // We have to be careful with overflowing operation. - if (bitLength(v1) >= SIZE - 1 - shifts) { - doOnBigInteger(v1, of(v2), result, BigInteger::multiply); - } else { - shiftLeft(v1, shifts, result); - } - } else { - doOnBigInteger(v1, of(v2), result, BigInteger::multiply); - } - } - - public static void multiplyModulo( - final Bytes32 v1, final Bytes32 v2, final Bytes32 modulo, final MutableBytes32 result) { - if (modulo.isZero()) { - result.clear(); - } else { - doOnBigInteger(v1, v2, modulo, result, (op1, op2, mod) -> op1.multiply(op2).mod(mod)); - } - } - - public static void divide(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - if (v2.isZero()) { - result.clear(); - } else { - doOnBigInteger(v1, v2, result, BigInteger::divide); - } - } - - // Assumes v > 0 - private static int log2(final long v) { - return 63 - Long.numberOfLeadingZeros(v); - } - - private static int maskByteRightBits(final int bits) { - return ~(0xFFFFFFFF << bits); - } - - @VisibleForTesting - static void shiftRight(final Bytes32 v1, final int v2, final MutableBytes32 result) { - final int d = v2 / 8; - final int s = v2 % 8; - int resIdx = SIZE - 1; - for (int i = SIZE - 1 - d; i >= 0; i--) { - final int leftSide = (v1.get(i) & 0xFF) >>> s; - final int rightSide = i == 0 ? 0 : v1.get(i - 1) << (8 - s); - result.set(resIdx--, (byte) (leftSide | rightSide)); - } - for (; resIdx >= 0; resIdx--) { - result.set(resIdx, (byte) 0); - } - } - - @VisibleForTesting - static void shiftLeft(final Bytes32 v1, final int v2, final MutableBytes32 result) { - final int d = v2 / 8; - final int s = v2 % 8; - int resIdx = 0; - for (int i = d; i < SIZE; i++) { - final int leftSide = v1.get(i) << s; - final int rightSide = i == SIZE - 1 ? 0 : (v1.get(i + 1) & 0xFF) >>> (8 - s); - result.set(resIdx++, (byte) (leftSide | rightSide)); - } - for (; resIdx < SIZE; resIdx++) { - result.set(resIdx, (byte) 0); - } - } - - public static void divide(final Bytes32 v1, final long v2, final MutableBytes32 result) { - if (v2 == 0) { - result.clear(); - } else if (v2 > 0 && isPowerOf2(v2)) { - shiftRight(v1, log2(v2), result); - } else { - doOnBigInteger(v1, of(v2), result, BigInteger::divide); - } - } - - public static void exponent(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - doOnBigInteger(v1, v2, result, (val, pow) -> val.modPow(pow, P256)); - } - - public static void modulo(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - if (v2.isZero()) { - result.clear(); - } else { - doOnBigInteger(v1, v2, result, BigInteger::mod); - } - } - - public static void modulo(final Bytes32 v1, final long v2, final MutableBytes32 result) { - if (v2 == 0) { - result.clear(); - } else if (v2 > 0 && isPowerOf2(v2)) { - final int log2 = log2(v2); - final int d = log2 / 8; - final int s = log2 % 8; - // Copy everything right of d - v1.slice(d + 1).copyTo(result, d + 1); - // Mask the byte at d to only include the s right-most bits ... - result.set(SIZE - 1 - d, (byte) (v1.get(SIZE - 1 - d) & maskByteRightBits(s))); - // and clear anything left of that d. - for (int i = d + 1; i < SIZE; i++) { - result.set(SIZE - 1 - i, (byte) 0); - } - } else { - doOnBigInteger(v1, of(v2), result, BigInteger::mod); - } - } - - public static void signExtend(final Bytes32 v1, final Bytes32 v2, final MutableBytes32 result) { - // Any value >= 31 imply an index <= 0, so no work to do (note that 0 itself is a valid index, - // but copying the 0th byte to itself is only so useful). - if (compareUnsigned(v2, U_31.getBytes()) >= 0) { - v1.copyTo(result); - return; - } - - // This is safe, since other < 31. - final int byteIndex = SIZE - 1 - v2.getInt(SIZE - 4); - final byte toSet = v1.get(byteIndex) < 0 ? ALL_ONE_BYTE : ALL_ZERO_BYTE; - result.mutableSlice(0, byteIndex).fill(toSet); - v1.slice(byteIndex).copyTo(result, byteIndex); - } - - // Other operations - - public static Bytes32 of(final long v) { - checkArgument(v >= 0, "Argument must be positive, got %s", v); - final MutableBytes32 bytes = MutableBytes32.create(); - bytes.setLong(Bytes32.SIZE - 8, v); - return bytes; - } - - public static Bytes32 of(final BigInteger v) { - checkArgument(v.signum() >= 0, "Argument must be positive, got %s", v); - BytesValue toCopy = BytesValue.wrap(v.toByteArray()); - // The result of BigInteger.toByteArray() contains the minimum amount of bytes needed to - // represent the number _plus_ "at least one sign bit". This mean in practice that if the - // (positive) number fits _exactly_ 256 bits, then it will have an extra 0 bit in front, so - // 257 bits which will be rounded up to 33 bytes. - checkArgument(toCopy.size() <= Bytes32.SIZE + 1, "Argument too big (%s bytes)", toCopy.size()); - - if (toCopy.size() == Bytes32.SIZE + 1) { - // Extra byte is due to sign bit. As the number has been checked to be positive, this must - // be 0 (or it mean the extra byte is truly due to the number being to big to represent with - // 32 bytes). - checkArgument(toCopy.get(0) == 0, "Argument too big (%s bytes)", toCopy.size()); - toCopy = toCopy.slice(1); - } - - final MutableBytes32 bytes = MutableBytes32.create(); - toCopy.copyTo(bytes, bytes.size() - toCopy.size()); - return bytes; - } - - static boolean fitsInt(final Bytes32 bytes) { - // Ints are 4 bytes, so anything but the 4 last bytes must be zeroes - for (int i = 0; i < SIZE - 4; i++) { - if (bytes.get(i) != 0) return false; - } - // Lastly, the left-most byte of the int must not start with a 1. - return bytes.get(SIZE - 4) >= 0; - } - - static boolean fitsLong(final Bytes32 bytes) { - // Longs are 8 bytes, so anything but the 8 last bytes must be zeroes - for (int i = 0; i < SIZE - 8; i++) { - if (bytes.get(i) != 0) return false; - } - // Lastly, the left-most byte of the long must not start with a 1. - return bytes.get(SIZE - 8) >= 0; - } - - static int bitLength(final Bytes32 bytes) { - for (int i = 0; i < SIZE; i++) { - final byte b = bytes.get(i); - if (b == 0) continue; - - return (SIZE * 8) - (i * 8) - (Integer.numberOfLeadingZeros(b & 0xFF) - 3 * 8); - } - return 0; - } - - static int compareUnsigned(final Bytes32 v1, final Bytes32 v2) { - for (int i = 0; i < SIZE; i++) { - final int cmp = Integer.compare((v1.get(i)) & 0xFF, (v2.get(i)) & 0xFF); - if (cmp != 0) return cmp; - } - return 0; - } - - static String toString(final Bytes32 v) { - return BytesValues.asUnsignedBigInteger(v).toString(); - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Value.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Value.java deleted file mode 100644 index 269a6a95..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256Value.java +++ /dev/null @@ -1,169 +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.utils.discoveryutils.bytes.uint; - -import io.xdag.utils.discoveryutils.bytes.Bytes32Backed; - -import static com.google.common.base.Preconditions.checkState; - -public interface UInt256Value> extends Bytes32Backed, Comparable { - - int SIZE = 32; - - /** @return An immutable copy of this value. */ - T copy(); - - /** @return True if this is the value 0. */ - default boolean isZero() { - return getBytes().isZero(); - } - - /** - * @return True if this value fits a java {@code int} (i.e. is less or equal to {@code - * Integer.MAX_VALUE}). - */ - default boolean fitsInt() { - return UInt256Bytes.fitsInt(getBytes()); - } - - /** - * @return This value as a java {@code int} assuming it is small enough to fit an {@code int}. - * @throws IllegalStateException if the value does not fit an {@code int}, that is if {@code - * !fitsInt()}. - */ - default int toInt() { - checkState(fitsInt(), "This scalar value does not fit a 4 byte int"); - return getBytes().getInt(SIZE - 4); - } - - /** - * @return True if this value fits a java {@code long} (i.e. is less or equal to {@code - * Long.MAX_VALUE}). - */ - default boolean fitsLong() { - return UInt256Bytes.fitsLong(getBytes()); - } - - /** - * @return This value as a java {@code long} assuming it is small enough to fit a {@code long}. - * @throws IllegalStateException if the value does not fit a {@code long}, that is if {@code - * !fitsLong()}. - */ - default long toLong() { - checkState(fitsLong(), "This scalar value does not fit a 8 byte long"); - return getBytes().getLong(SIZE - 8); - } - - T plus(T value); - - T plus(long value); - - T plusModulo(T value, UInt256 modulo); - - T minus(T value); - - T minus(long value); - - T times(T value); - - T times(long value); - - T timesModulo(T value, UInt256 modulo); - - T dividedBy(T value); - - T dividedBy(long value); - - default T dividedCeilBy(final long value) { - final T res = dividedBy(value); - return mod(value).isZero() ? res : res.plus(1); - } - - T pow(T value); - - T mod(T value); - - T mod(long value); - - Int256 signExtent(UInt256 value); - - T and(T value); - - T or(T value); - - T xor(T value); - - T not(); - - /** @return The number of bits in the minimal (in term of bits) representation of this value. */ - default int bitLength() { - return UInt256Bytes.bitLength(getBytes()); - } - - /** @return A view of the bytes of this number as signed (two's complement). */ - default Int256 asSigned() { - return new DefaultInt256(getBytes()); - } - - /** - * This value represented as an hexadecimal string. - * - *

Note that this representation includes all the 32 underlying bytes, no matter what the - * integer actually represents (in other words, it can have many leading zeros). For a shorter - * representation that don't include leading zeros, use {@link #toShortHexString}. - * - * @return This value represented as an hexadecimal string. - */ - default String toHexString() { - return getBytes().toString(); - } - - /** @return This value represented as a minimal hexadecimal string (without any leading zero). */ - default String toShortHexString() { - final String hex = toHexString(); - // Skipping '0x' - if (hex.charAt(2) != '0') return hex; - - int i = 3; - while (i < hex.length() - 1 && hex.charAt(i) == '0') { - i++; - } - return "0x" + hex.substring(i); - } - - /** @return This value represented as an hexadecimal string without a 0x prefix. */ - default String toUnprefixedHexString() { - return toHexString().substring(2); - } - - /** - * Type-cast this value as a {@link UInt256}. - * - *

Note that the returned {@link UInt256} is a type-casted "view" of this value, and so if this - * value is mutable and is muted, the returned {@link UInt256} will reflect those changes. - * - * @return This value as a {@link UInt256}. - */ - UInt256 asUInt256(); -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256s.java b/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256s.java deleted file mode 100644 index 52266476..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/bytes/uint/UInt256s.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.utils.discoveryutils.bytes.uint; - -public class UInt256s { - - /** - * Returns the maximum of 2 UInt256 values. - * - * @param v1 The first value. - * @param v2 The second value. - * @return The maximum of {@code v1} and {@code v2}. - * @param The concrete type of the two values. - */ - public static > T max(final T v1, final T v2) { - return (v1.compareTo(v2)) >= 0 ? v1 : v2; - } - - /** - * Returns the minimum of 2 UInt256 values. - * - * @param v1 The first value. - * @param v2 The second value. - * @return The minimum of {@code v1} and {@code v2}. - * @param The concrete type of the two values. - */ - public static > T min(final T v1, final T v2) { - return (v1.compareTo(v2)) < 0 ? v1 : v2; - } - - public static > boolean greaterThanOrEqualTo256(final T uint256) { - return uint256.bitLength() > 8; - } -} diff --git a/src/main/java/io/xdag/utils/discoveryutils/cryto/Hash.java b/src/main/java/io/xdag/utils/discoveryutils/cryto/Hash.java deleted file mode 100644 index 08312f6c..00000000 --- a/src/main/java/io/xdag/utils/discoveryutils/cryto/Hash.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.utils.discoveryutils.cryto; - -import io.xdag.utils.XdagSha256Digest; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import io.xdag.utils.discoveryutils.BouncyCastleMessageDigestFactory; -import io.xdag.utils.discoveryutils.bytes.Bytes32; -import io.xdag.utils.discoveryutils.bytes.BytesValue; - -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Security; - -public abstract class Hash { - private Hash() {} - - static { - Security.addProvider(new BouncyCastleProvider()); - } - - private static byte[] digestUsingAlgorithm(final BytesValue input, final String alg) { - final MessageDigest digest; - try { - digest = BouncyCastleMessageDigestFactory.create(alg); - input.update(digest); - return digest.digest(); - } catch (final NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - } - - public static Bytes32 sha256(final BytesValue input) throws IOException { - byte[] tmp = input.extractArray(); - XdagSha256Digest xdagSha256Digest = new XdagSha256Digest(); - return Bytes32.wrap(xdagSha256Digest.sha256Final(tmp)); - } -} diff --git a/src/main/java/io/xdag/wallet/OldWallet.java b/src/main/java/io/xdag/wallet/OldWallet.java index 460ca3c5..3da14a0e 100644 --- a/src/main/java/io/xdag/wallet/OldWallet.java +++ b/src/main/java/io/xdag/wallet/OldWallet.java @@ -27,6 +27,7 @@ import io.xdag.crypto.ECKeyPair; import io.xdag.crypto.Keys; import io.xdag.crypto.jni.Native; +import io.xdag.utils.BytesUtils; import io.xdag.utils.FileUtils; import io.xdag.utils.Numeric; import org.apache.commons.io.IOUtils; @@ -194,6 +195,7 @@ private void pasreWalletDat() throws Exception { byte[] priv32Encrypted = new byte[32]; while (fileInputStream.read(priv32Encrypted) != -1) { byte[] priv32 = Native.uncrypt_wallet_key(priv32Encrypted, keysNum++); + BytesUtils.arrayReverse(priv32); ECKeyPair ecKey = ECKeyPair.create(Numeric.toBigInt(priv32)); // 奇偶 boolean pubKeyParity = !ecKey.getPublicKey().testBit(0); diff --git a/src/main/java/io/xdag/wallet/WalletUtils.java b/src/main/java/io/xdag/wallet/WalletUtils.java index 53de60fd..b99da11c 100644 --- a/src/main/java/io/xdag/wallet/WalletUtils.java +++ b/src/main/java/io/xdag/wallet/WalletUtils.java @@ -35,6 +35,8 @@ public class WalletUtils { // https://github.com/satoshilabs/slips/blob/master/slip-0044.md public static final int XDAG_BIP44_CION_TYPE = 586; + public static final String WALLET_PASSWORD_PROMPT = "Please Enter Wallet Password: "; + public static Bip32ECKeyPair generateBip44KeyPair(Bip32ECKeyPair master, int index) { // m/44'/586'/0'/0/0 // xdag coin type 586 at https://github.com/satoshilabs/slips/blob/master/slip-0044.md diff --git a/src/main/resources/xdag-mainnet.config b/src/main/resources/xdag-mainnet.config index bba68628..1f608d9d 100644 --- a/src/main/resources/xdag-mainnet.config +++ b/src/main/resources/xdag-mainnet.config @@ -32,3 +32,5 @@ maxMinerPerAccount = 256 password = root whiteIPs = + +bootnode = enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR diff --git a/src/main/resources/xdag-testnet.config b/src/main/resources/xdag-testnet.config index f6c08249..ab9ae0b8 100644 --- a/src/main/resources/xdag-testnet.config +++ b/src/main/resources/xdag-testnet.config @@ -33,5 +33,6 @@ password = root whiteIPs = -isRPCEnabled = true +bootnode = enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR +isRPCEnabled = true diff --git a/src/test/java/io/xdag/cli/XdagCliTest.java b/src/test/java/io/xdag/cli/XdagCliTest.java index 0cb6ef24..f66bbd90 100644 --- a/src/test/java/io/xdag/cli/XdagCliTest.java +++ b/src/test/java/io/xdag/cli/XdagCliTest.java @@ -31,6 +31,7 @@ import io.xdag.crypto.Keys; import io.xdag.utils.BytesUtils; import io.xdag.wallet.Wallet; +import org.assertj.core.util.Lists; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -47,6 +48,8 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.*; +import static org.mockito.Mockito.spy; +import static io.xdag.wallet.WalletUtils.WALLET_PASSWORD_PROMPT; public class XdagCliTest { private Config config; @@ -84,6 +87,7 @@ public void testVersion() throws Exception { @Test public void testMainnet() throws Exception { XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(new MainnetConfig()); // mock accounts List accounts = new ArrayList<>(); @@ -95,9 +99,10 @@ public void testMainnet() throws Exception { when(wallet.unlock("oldpassword")).thenReturn(true); when(wallet.getAccounts()).thenReturn(accounts); when(wallet.exists()).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(any()); doReturn(null).when(xdagCLI).startKernel(any(), any()); xdagCLI.start(new String[] {""}); @@ -107,6 +112,7 @@ public void testMainnet() throws Exception { @Test public void testTestnet() throws Exception { XdagCli xdagCLI = spy(new XdagCli()); + xdagCLI.setConfig(new TestnetConfig()); // mock accounts List accounts = new ArrayList<>(); @@ -118,9 +124,10 @@ public void testTestnet() throws Exception { when(wallet.unlock("oldpassword")).thenReturn(true); when(wallet.getAccounts()).thenReturn(accounts); when(wallet.exists()).thenReturn(true); + when(xdagCLI.loadWallet()).thenReturn(wallet); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); xdagCLI.start(new String[] {"-t"}); @@ -166,7 +173,7 @@ public void testStartKernelWithEmptyWallet() throws Exception { when(wallet.addAccountWithNextHdKey()).thenReturn(newAccount); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn("oldpassword").when(xdagCLI).readNewPassword(any(), any()); doReturn(null).when(xdagCLI).startKernel(any(), any()); @@ -252,7 +259,7 @@ public void testCreateAccount() throws Exception { when(wallet.addAccountWithNextHdKey()).thenReturn(newAccount); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -280,7 +287,7 @@ public void testListAccounts() throws Exception { when(xdagCLI.loadWallet()).thenReturn(wallet); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -303,7 +310,7 @@ public void testChangePasswordIncorrectConfirmation() { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn("a").doReturn("b").when(xdagCLI).readPassword(any()); doNothing().when(xdagCLI).exit(anyInt()); @@ -329,7 +336,7 @@ public void testDumpPrivateKey() throws Exception { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -357,7 +364,7 @@ public void testDumpPrivateKeyNotFound() throws Exception { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -381,7 +388,7 @@ public void testImportPrivateKeyExisted() throws Exception { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -406,7 +413,7 @@ public void testImportPrivateKeyFailedToFlushWalletFile() throws Exception { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -430,7 +437,7 @@ public void testImportPrivateKey() throws Exception { when(wallet.isHdWalletInitialized()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -453,7 +460,7 @@ public void testImportMnemonic() throws Exception { when(wallet.flush()).thenReturn(true); // mock passwords - doReturn("oldpassword").when(xdagCLI).readPassword(); + doReturn("oldpassword").when(xdagCLI).readPassword(WALLET_PASSWORD_PROMPT); doReturn(null).when(xdagCLI).startKernel(any(), any()); // execution @@ -461,4 +468,24 @@ public void testImportMnemonic() throws Exception { assertTrue(xdagCLI.importMnemonic(rightMnemonic)); } -} \ No newline at end of file + @Test + public void testConvertOldWallet() { + XdagCli xdagCLI = spy(new XdagCli()); + File walletFile = spy(new File("")); + xdagCLI.setConfig(config); + String hexPrivKey = "008f30bc86f42f55d8d64dd26a5428fc1e65f0616823153c084b43aad76cd97e04"; + byte[] keyBytes = BytesUtils.hexStringToBytes(hexPrivKey); + ECKeyPair account = ECKeyPair.create(keyBytes); + List keyList = Lists.newArrayList(account); + + // mock wallet + doReturn(keyList).when(xdagCLI).readOldWallet("111111", "111111", walletFile); + when(walletFile.exists()).thenReturn(true); + // mock passwords + doReturn("111111").when(xdagCLI).readPassword("Old wallet password:"); + doReturn("111111").when(xdagCLI).readPassword("Old wallet random:"); + + assertTrue(xdagCLI.convertOldWallet(walletFile)); + } + +} diff --git a/src/test/java/io/xdag/nat/NatManagerTest.java b/src/test/java/io/xdag/net/nat/NatManagerTest.java similarity index 99% rename from src/test/java/io/xdag/nat/NatManagerTest.java rename to src/test/java/io/xdag/net/nat/NatManagerTest.java index 8d5ca8d8..fee89683 100644 --- a/src/test/java/io/xdag/nat/NatManagerTest.java +++ b/src/test/java/io/xdag/net/nat/NatManagerTest.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.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import org.assertj.core.api.Assertions; diff --git a/src/test/java/io/xdag/nat/NatServiceTest.java b/src/test/java/io/xdag/net/nat/NatServiceTest.java similarity index 99% rename from src/test/java/io/xdag/nat/NatServiceTest.java rename to src/test/java/io/xdag/net/nat/NatServiceTest.java index 13bccc14..5e0dd95e 100644 --- a/src/test/java/io/xdag/nat/NatServiceTest.java +++ b/src/test/java/io/xdag/net/nat/NatServiceTest.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.nat; +package io.xdag.net.nat; import io.xdag.utils.SafeFuture; import org.junit.Test; diff --git a/src/test/java/io/xdag/nat/NatServiceTypeTest.java b/src/test/java/io/xdag/net/nat/NatServiceTypeTest.java similarity index 98% rename from src/test/java/io/xdag/nat/NatServiceTypeTest.java rename to src/test/java/io/xdag/net/nat/NatServiceTypeTest.java index d0fcc9fa..2e72cdbd 100644 --- a/src/test/java/io/xdag/nat/NatServiceTypeTest.java +++ b/src/test/java/io/xdag/net/nat/NatServiceTypeTest.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.nat; +package io.xdag.net.nat; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/src/test/java/io/xdag/nat/UpnpClientTest.java b/src/test/java/io/xdag/net/nat/UpnpClientTest.java similarity index 99% rename from src/test/java/io/xdag/nat/UpnpClientTest.java rename to src/test/java/io/xdag/net/nat/UpnpClientTest.java index afc2eaae..5fd15ad9 100644 --- a/src/test/java/io/xdag/nat/UpnpClientTest.java +++ b/src/test/java/io/xdag/net/nat/UpnpClientTest.java @@ -21,7 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package io.xdag.nat; +package io.xdag.net.nat; + import io.xdag.utils.SafeFuture; import org.junit.Before; @@ -44,8 +45,8 @@ import java.net.URL; import java.util.Optional; -import static org.mockito.Mockito.*; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.Mockito.*; public class UpnpClientTest { private UpnpService natService = mock(UpnpService.class); diff --git a/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java b/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java index 960bd321..027f17a0 100644 --- a/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java +++ b/src/test/java/io/xdag/rpc/modules/XdagModuleTest.java @@ -6,7 +6,6 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; diff --git a/src/test/java/io/xdag/utils/BasicUtilsTest.java b/src/test/java/io/xdag/utils/BasicUtilsTest.java index 237dc727..606c4726 100644 --- a/src/test/java/io/xdag/utils/BasicUtilsTest.java +++ b/src/test/java/io/xdag/utils/BasicUtilsTest.java @@ -23,13 +23,12 @@ */ package io.xdag.utils; -import org.bouncycastle.util.encoders.Hex; -import org.junit.Test; +import static org.junit.Assert.assertEquals; import java.math.BigDecimal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Test; public class BasicUtilsTest { @@ -61,6 +60,14 @@ public void amount2xdag() { // 400 0000 0000? assertEquals(1.49, BasicUtils.amount2xdag(6400000000L), 0.0); + // Xfer:transferred 44796588980 10.430000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 10.43 + assertEquals(10.43, BasicUtils.amount2xdag(44796588980L), 0.0); + + // Xfer:transferred 42949672960 10.000000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 10 + assertEquals(10.0, BasicUtils.amount2xdag(42949672960L), 0.0); + + // Xfer:transferred 4398046511104 1024.000000000 XDAG to the address 0000002f28322e9d817fd94a1357e51a. 1024 + assertEquals(1024.0, BasicUtils.amount2xdag(4398046511104L), 0.0); } @Test diff --git a/src/test/resources/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json b/src/test/resources/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json deleted file mode 100644 index 1b72ed27..00000000 --- a/src/test/resources/keyfiles/UTC--2021-04-08T13-00-52.556433000Z--a15339b55796b3585127c180fd4cbc54612122cf.json +++ /dev/null @@ -1 +0,0 @@ -{"address":"a15339b55796b3585127c180fd4cbc54612122cf","id":"2959492c-8805-4607-bb31-9599887716e5","version":3,"crypto":{"cipher":"aes-128-ctr","ciphertext":"27e54ee65aebc5f3fdeb27afc1c8bb3e51e04f6f95fa15d3e4a3c8cfc52cb360","cipherparams":{"iv":"50911b0ed68ba3d3732de8f592c092f6"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"a5c1165499166d279c541a9ec9844647344f85d8cab8fd1b55172590a8c63267"},"mac":"fb14c6f878a50228ba27bcd758348dc003d59545da2437f0cd0fa2c7f3aa5efb"}} \ No newline at end of file From 06fc1d81d1e163628c4ba8c146d9a8bc8991dfe9 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 19:42:30 +0800 Subject: [PATCH 07/11] modify --- .../java/io/xdag/config/RandomXConstants.java | 2 +- src/main/java/io/xdag/core/ImportResult.java | 2 +- .../java/io/xdag/mine/handler/Miner03.java | 2 +- .../java/io/xdag/rpc/dto/BlockResultDTO.java | 3 +- src/main/java/io/xdag/rpc/dto/StatusDTO.java | 1 + .../xdag/rpc/dto/TransactionReceiptDTO.java | 1 + .../xdag/XdagModuleTransactionBase.java | 2 +- src/main/resources/rpc_modules.conf | 55 ------------------- 8 files changed, 8 insertions(+), 60 deletions(-) diff --git a/src/main/java/io/xdag/config/RandomXConstants.java b/src/main/java/io/xdag/config/RandomXConstants.java index be3e84c5..4c24e795 100644 --- a/src/main/java/io/xdag/config/RandomXConstants.java +++ b/src/main/java/io/xdag/config/RandomXConstants.java @@ -32,7 +32,7 @@ public class RandomXConstants { public static long SEEDHASH_EPOCH_TESTNET_LAG = 64; public static final long RANDOMX_FORK_HEIGHT = 1540096; - public static long RANDOMX_TESTNET_FORK_HEIGHT = 409600000;// 196288 + public static long RANDOMX_TESTNET_FORK_HEIGHT = 4096;// 196288 public static final int XDAG_RANDOMX = 2; diff --git a/src/main/java/io/xdag/core/ImportResult.java b/src/main/java/io/xdag/core/ImportResult.java index 94c61f01..539b7ad4 100644 --- a/src/main/java/io/xdag/core/ImportResult.java +++ b/src/main/java/io/xdag/core/ImportResult.java @@ -51,7 +51,7 @@ public String getErrorInfo() { return errorInfo; } - public boolean isLegal() { + public boolean isNormal() { return this == IMPORTED_NOT_BEST || this == IMPORTED_BEST || this == EXIST; } } diff --git a/src/main/java/io/xdag/mine/handler/Miner03.java b/src/main/java/io/xdag/mine/handler/Miner03.java index a1e45835..2125cfe4 100644 --- a/src/main/java/io/xdag/mine/handler/Miner03.java +++ b/src/main/java/io/xdag/mine/handler/Miner03.java @@ -97,7 +97,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { protected void processNewBlock(NewBlockMessage msg) { Block block = msg.getBlock(); ImportResult importResult = syncManager.validateAndAddNewBlock(new BlockWrapper(block, kernel.getConfig().getNodeSpec().getTTL())); - if (importResult.isLegal()) { + if (importResult.isNormal()) { log.info("XDAG:receive tansaction. A Transaction from wallet/miner, block hash:{}", Hex.toHexString(block.getHash())); } } diff --git a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java index 4025266d..8a710d86 100644 --- a/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java +++ b/src/main/java/io/xdag/rpc/dto/BlockResultDTO.java @@ -28,6 +28,7 @@ import lombok.Data; @Data +//TODO: Return xdagblock info public class BlockResultDTO { // blockInfo @@ -37,7 +38,7 @@ public class BlockResultDTO { public BlockResultDTO(long height) { this.height = Long.toHexString(height); - this.data = "hello"; + this.data = "0x"; } diff --git a/src/main/java/io/xdag/rpc/dto/StatusDTO.java b/src/main/java/io/xdag/rpc/dto/StatusDTO.java index ecd89462..eedda91c 100644 --- a/src/main/java/io/xdag/rpc/dto/StatusDTO.java +++ b/src/main/java/io/xdag/rpc/dto/StatusDTO.java @@ -30,6 +30,7 @@ import static io.xdag.rpc.utils.TypeConverter.toQuantityJsonHex; @Data +//TODO: return xdag status public class StatusDTO { // status 状态信息 private final String nblocks; diff --git a/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java index 356cb0da..79485aa7 100644 --- a/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java +++ b/src/main/java/io/xdag/rpc/dto/TransactionReceiptDTO.java @@ -23,6 +23,7 @@ */ package io.xdag.rpc.dto; +// TODO: return transaction receipt public class TransactionReceiptDTO { diff --git a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java index a5d0a8ba..ab14be43 100644 --- a/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java +++ b/src/main/java/io/xdag/rpc/modules/xdag/XdagModuleTransactionBase.java @@ -71,7 +71,7 @@ public String sendRawTransaction(String rawData) { Block block = new Block(new XdagBlock(Hex.decode(rawData))); ImportResult result = blockchain.tryToConnect(block); System.out.println(result); - if (!result.isLegal()) { + if (!result.isNormal()) { return "0x"; } else { return result.toString(); diff --git a/src/main/resources/rpc_modules.conf b/src/main/resources/rpc_modules.conf index 4b91b3f9..1252ee90 100644 --- a/src/main/resources/rpc_modules.conf +++ b/src/main/resources/rpc_modules.conf @@ -37,60 +37,5 @@ rpc { version: "1.0", enabled: "true", }, -; { -; name: "eth", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "net", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "rpc", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "web3", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "evm", -; version: "1.0", -; enabled: "true" -; }, -; { -; name: "sco", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "txpool", -; version: "1.0", -; enabled: "true", -; }, -; { -; name: "personal", -; version: "1.0", -; enabled: "true" -; }, -; { -; name: "debug", -; version: "1.0", -; enabled: "true" -; }, -; { -; name: "trace", -; version: "1.0", -; enabled: "true" -; }, -; { -; name: "rsk", -; version: "1.0", -; enabled: "true" -; } ] } From 4e2cc8c108db88356b2622f2c9d83ee72886b4d2 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 19:46:21 +0800 Subject: [PATCH 08/11] modify --- src/main/java/io/xdag/Kernel.java | 4 +- src/main/java/io/xdag/wallet/WalletUtils.java | 2 +- src/test/java/io/xdag/cli/XdagCliTest.java | 2 +- .../net/discovery/DiscoveryNetworkTest.java | 24 ++++ .../xdag/net/discovery/DiscoveryPeerTest.java | 66 ++++++++++ .../discovery/discv5/DiscoveryPeerTest.java | 36 ++++++ .../discv5/NodeRecordConverterTest.java | 116 ++++++++++++++++++ .../io/xdag/net/libp2p/Libp2pNetworkTest.java | 55 +++++++++ src/test/java/io/xdag/wallet/WalletTest.java | 2 +- 9 files changed, 302 insertions(+), 5 deletions(-) create mode 100644 src/test/java/io/xdag/net/discovery/DiscoveryNetworkTest.java create mode 100644 src/test/java/io/xdag/net/discovery/DiscoveryPeerTest.java create mode 100644 src/test/java/io/xdag/net/discovery/discv5/DiscoveryPeerTest.java create mode 100644 src/test/java/io/xdag/net/discovery/discv5/NodeRecordConverterTest.java create mode 100644 src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 13b74715..80499c0a 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -358,7 +358,7 @@ private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException private Web3HttpServer getWeb3HttpServer() throws UnknownHostException { if (web3HttpServer == null) { web3HttpServer = new Web3HttpServer( - InetAddress.getByName("192.168.3.229"), + InetAddress.getByName("127.0.0.1"), 4445, 123, true, @@ -375,7 +375,7 @@ private JsonRpcWeb3FilterHandler getJsonRpcWeb3FilterHandler() throws UnknownHos if (jsonRpcWeb3FilterHandler == null) { jsonRpcWeb3FilterHandler = new JsonRpcWeb3FilterHandler( "*", - InetAddress.getByName("192.168.3.229"), + InetAddress.getByName("127.0.0.1"), null ); } diff --git a/src/main/java/io/xdag/wallet/WalletUtils.java b/src/main/java/io/xdag/wallet/WalletUtils.java index b99da11c..5660f431 100644 --- a/src/main/java/io/xdag/wallet/WalletUtils.java +++ b/src/main/java/io/xdag/wallet/WalletUtils.java @@ -51,4 +51,4 @@ public static Bip32ECKeyPair importMnemonic(Wallet wallet, String password, Stri return generateBip44KeyPair(masterKeypair, index); } -} +} \ No newline at end of file diff --git a/src/test/java/io/xdag/cli/XdagCliTest.java b/src/test/java/io/xdag/cli/XdagCliTest.java index f66bbd90..6f4d7374 100644 --- a/src/test/java/io/xdag/cli/XdagCliTest.java +++ b/src/test/java/io/xdag/cli/XdagCliTest.java @@ -488,4 +488,4 @@ public void testConvertOldWallet() { assertTrue(xdagCLI.convertOldWallet(walletFile)); } -} +} \ No newline at end of file diff --git a/src/test/java/io/xdag/net/discovery/DiscoveryNetworkTest.java b/src/test/java/io/xdag/net/discovery/DiscoveryNetworkTest.java new file mode 100644 index 00000000..411cf50e --- /dev/null +++ b/src/test/java/io/xdag/net/discovery/DiscoveryNetworkTest.java @@ -0,0 +1,24 @@ +package io.xdag.net.discovery; + +import io.xdag.net.discovery.discv5.DiscV5ServiceImpl; +import io.xdag.utils.SafeFuture; +import org.junit.Test; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +public class DiscoveryNetworkTest { + private final DiscV5ServiceImpl discoveryService = mock(DiscV5ServiceImpl.class); + + @Test + public void DiscoveryStart() { + final SafeFuture discoveryStart = new SafeFuture<>(); + doReturn(discoveryStart).when(discoveryService).start(); + } + @Test + @SuppressWarnings({"FutureReturnValueIgnored"}) + public void shouldStopNetworkAndDiscoveryWhenConnectionManagerStopFails() { + doReturn(new SafeFuture()).when(discoveryService).stop(); + } + +} diff --git a/src/test/java/io/xdag/net/discovery/DiscoveryPeerTest.java b/src/test/java/io/xdag/net/discovery/DiscoveryPeerTest.java new file mode 100644 index 00000000..8f9b63cc --- /dev/null +++ b/src/test/java/io/xdag/net/discovery/DiscoveryPeerTest.java @@ -0,0 +1,66 @@ +package io.xdag.net.discovery; + +import io.libp2p.core.crypto.KEY_TYPE; +import io.libp2p.core.crypto.KeyKt; +import io.libp2p.core.crypto.PrivKey; +import io.xdag.net.discovery.discv5.DiscV5ServiceImpl; +import org.apache.tuweni.bytes.Bytes; +import org.bouncycastle.util.encoders.Hex; +import org.junit.Before; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +public class DiscoveryPeerTest { + DiscoveryService discV5Service1; + DiscoveryService discV5Service2; + DiscoveryService discV5Service3; + 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 = new ArrayList<>(); + Bytes bytes = Bytes.wrap(privKey.raw()); + discV5Service1 = DiscV5ServiceImpl.create((bytes), + "127.0.0.1", + 10001, + Collections.emptyList()); + if(discV5Service1.getEnr().isPresent()){ + boot.add(discV5Service1.getEnr().get()); + System.out.println(discV5Service1.getEnr().get()); + } + discV5Service2 = DiscV5ServiceImpl.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() { + if(discV5Service2.streamKnownPeers().findFirst().isPresent()){ + assert discoveryPeer.equals(discV5Service2.streamKnownPeers().findFirst().get()); + } + } + +} \ No newline at end of file diff --git a/src/test/java/io/xdag/net/discovery/discv5/DiscoveryPeerTest.java b/src/test/java/io/xdag/net/discovery/discv5/DiscoveryPeerTest.java new file mode 100644 index 00000000..9c2c77ed --- /dev/null +++ b/src/test/java/io/xdag/net/discovery/discv5/DiscoveryPeerTest.java @@ -0,0 +1,36 @@ +package io.xdag.net.discovery.discv5; + +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.discovery.DiscoveryPeer; +import io.xdag.net.libp2p.peer.DiscoveryPeerConverter; +import io.xdag.net.libp2p.peer.LibP2PNodeId; +import org.apache.tuweni.bytes.Bytes; +import org.junit.Before; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; + +import static org.junit.Assert.assertEquals; + +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, DiscoveryPeerConverter.discoveryPeerToDailId(peer)); + } +} diff --git a/src/test/java/io/xdag/net/discovery/discv5/NodeRecordConverterTest.java b/src/test/java/io/xdag/net/discovery/discv5/NodeRecordConverterTest.java new file mode 100644 index 00000000..4f0fceda --- /dev/null +++ b/src/test/java/io/xdag/net/discovery/discv5/NodeRecordConverterTest.java @@ -0,0 +1,116 @@ +package io.xdag.net.discovery.discv5; + +import io.xdag.net.discovery.DiscoveryPeer; +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; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Optional; + +import static io.xdag.net.discovery.discv5.NodeRecordConverter.convertToDiscoveryPeer; +import static org.assertj.core.api.Assertions.assertThat; + +public class NodeRecordConverterTest { + + 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/Libp2pNetworkTest.java b/src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java new file mode 100644 index 00000000..3b7a1203 --- /dev/null +++ b/src/test/java/io/xdag/net/libp2p/Libp2pNetworkTest.java @@ -0,0 +1,55 @@ +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.LibP2PNodeId; +import io.xdag.net.libp2p.peer.NodeId; +import io.xdag.utils.MultiaddrUtil; +import org.junit.Before; +import org.junit.Test; + +import java.net.InetSocketAddress; + +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 = + MultiaddrUtil.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 = + MultiaddrUtil.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 { + assert node0.peerManager.getPeerCount() == 0; + assert node1.peerManager.getPeerCount() == 0; + // 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; + + + } +} \ No newline at end of file diff --git a/src/test/java/io/xdag/wallet/WalletTest.java b/src/test/java/io/xdag/wallet/WalletTest.java index 5a1582ca..e7df388e 100644 --- a/src/test/java/io/xdag/wallet/WalletTest.java +++ b/src/test/java/io/xdag/wallet/WalletTest.java @@ -195,4 +195,4 @@ public void testHDKeyRecover() { public void tearDown() throws IOException { wallet.delete(); } -} +} \ No newline at end of file From 2d3fbabbc33ecf853a9bdce07db262471006ee6c Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 20:27:16 +0800 Subject: [PATCH 09/11] modify --- src/main/java/io/xdag/Kernel.java | 14 ++++---- .../java/io/xdag/config/AbstractConfig.java | 32 +++++++++++++++++-- src/main/java/io/xdag/config/Config.java | 11 +++---- .../java/io/xdag/config/spec/RPCSpec.java | 13 ++++++++ src/main/resources/xdag-mainnet.config | 5 +++ src/main/resources/xdag-testnet.config | 3 ++ 6 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 src/main/java/io/xdag/config/spec/RPCSpec.java diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java index 80499c0a..b641d787 100644 --- a/src/main/java/io/xdag/Kernel.java +++ b/src/main/java/io/xdag/Kernel.java @@ -303,7 +303,7 @@ public synchronized void testStart() throws Exception { // ==================================== // rpc start // ==================================== - if (config.isRPCEnabled()) { + if (config.getRPCSpec().isRPCEnabled()) { getWeb3HttpServer().start(); getWeb3WebSocketServer().start(); } @@ -333,7 +333,7 @@ private JsonRpcWeb3ServerHandler getJsonRpcWeb3ServerHandler() { if (jsonRpcWeb3ServerHandler == null) { jsonRpcWeb3ServerHandler = new JsonRpcWeb3ServerHandler( getWeb3(), - config.getRpcModules() + config.getRPCSpec().getRpcModules() ); } @@ -345,8 +345,8 @@ private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException JsonRpcSerializer jsonRpcSerializer = getJsonRpcSerializer(); XdagJsonRpcHandler jsonRpcHandler = new XdagJsonRpcHandler(jsonRpcSerializer); web3WebSocketServer = new Web3WebSocketServer( - InetAddress.getByName("127.0.0.1"), - 4444, + InetAddress.getByName(config.getRPCSpec().getRPCHost()), + config.getRPCSpec().getRPCPortByWebSocket(), jsonRpcHandler, getJsonRpcWeb3ServerHandler() ); @@ -358,8 +358,8 @@ private Web3WebSocketServer getWeb3WebSocketServer() throws UnknownHostException private Web3HttpServer getWeb3HttpServer() throws UnknownHostException { if (web3HttpServer == null) { web3HttpServer = new Web3HttpServer( - InetAddress.getByName("127.0.0.1"), - 4445, + InetAddress.getByName(config.getRPCSpec().getRPCHost()), + config.getRPCSpec().getRPCPortByHttp(), 123, true, new CorsConfiguration("*"), @@ -375,7 +375,7 @@ private JsonRpcWeb3FilterHandler getJsonRpcWeb3FilterHandler() throws UnknownHos if (jsonRpcWeb3FilterHandler == null) { jsonRpcWeb3FilterHandler = new JsonRpcWeb3FilterHandler( "*", - InetAddress.getByName("127.0.0.1"), + InetAddress.getByName(config.getRPCSpec().getRPCHost()), null ); } diff --git a/src/main/java/io/xdag/config/AbstractConfig.java b/src/main/java/io/xdag/config/AbstractConfig.java index bb4f4a1f..3f07a9b9 100644 --- a/src/main/java/io/xdag/config/AbstractConfig.java +++ b/src/main/java/io/xdag/config/AbstractConfig.java @@ -45,7 +45,7 @@ @Slf4j @Getter @Setter -public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, WalletSpec { +public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, WalletSpec, RPCSpec { protected String configName; // ========================= @@ -135,7 +135,9 @@ public class AbstractConfig implements Config, AdminSpec, PoolSpec, NodeSpec, Wa // ========================= protected List moduleDescriptions; protected boolean rpcEnabled = false; - + protected String rpcHost; + protected int rpcPortHttp; + protected int rpcPortWs; public void setDir() { storeDir = getRootDir() + "/rocksdb/xdagdb"; @@ -177,6 +179,11 @@ public void initKeys() throws Exception { } } + @Override + public RPCSpec getRPCSpec() { + return this; + } + @Override public PoolSpec getPoolSpec() { return this; @@ -236,7 +243,13 @@ public void getSetting() { if (bootnodelist != null) { bootnodes.addAll(Arrays.asList(bootnodelist)); } + // rpc rpcEnabled = setting.getBool("isRPCEnabled") != null && setting.getBool("isRPCEnabled"); + if (rpcEnabled) { + rpcHost = setting.getStr("rpcHost"); + rpcPortHttp = setting.getInt("rpcPort_http"); + rpcPortWs = setting.getInt("rpcPort_ws"); + } } @Override @@ -376,4 +389,19 @@ public List getRpcModules() { public boolean isRPCEnabled() { return rpcEnabled; } + + @Override + public String getRPCHost() { + return rpcHost; + } + + @Override + public int getRPCPortByHttp() { + return rpcPortHttp; + } + + @Override + public int getRPCPortByWebSocket() { + return rpcPortWs; + } } diff --git a/src/main/java/io/xdag/config/Config.java b/src/main/java/io/xdag/config/Config.java index 9460bff0..3b1d118d 100644 --- a/src/main/java/io/xdag/config/Config.java +++ b/src/main/java/io/xdag/config/Config.java @@ -23,10 +23,7 @@ */ package io.xdag.config; -import io.xdag.config.spec.AdminSpec; -import io.xdag.config.spec.PoolSpec; -import io.xdag.config.spec.NodeSpec; -import io.xdag.config.spec.WalletSpec; +import io.xdag.config.spec.*; import io.xdag.core.XdagField; import io.xdag.rpc.modules.ModuleDescription; @@ -82,7 +79,7 @@ public interface Config { void initKeys() throws Exception; // rpc - List getRpcModules(); - boolean isRPCEnabled(); - +// List getRpcModules(); +// boolean isRPCEnabled(); + RPCSpec getRPCSpec(); } diff --git a/src/main/java/io/xdag/config/spec/RPCSpec.java b/src/main/java/io/xdag/config/spec/RPCSpec.java new file mode 100644 index 00000000..1781e2e1 --- /dev/null +++ b/src/main/java/io/xdag/config/spec/RPCSpec.java @@ -0,0 +1,13 @@ +package io.xdag.config.spec; + +import io.xdag.rpc.modules.ModuleDescription; + +import java.util.List; + +public interface RPCSpec { + List getRpcModules(); + boolean isRPCEnabled(); + String getRPCHost(); + int getRPCPortByHttp(); + int getRPCPortByWebSocket(); +} diff --git a/src/main/resources/xdag-mainnet.config b/src/main/resources/xdag-mainnet.config index 1f608d9d..702cffcf 100644 --- a/src/main/resources/xdag-mainnet.config +++ b/src/main/resources/xdag-mainnet.config @@ -34,3 +34,8 @@ password = root whiteIPs = bootnode = enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR + +isRPCEnabled = true +rpcHost = 127.0.0.1 +rpcPort_http = 4444 +rpcPort_ws = 4445 diff --git a/src/main/resources/xdag-testnet.config b/src/main/resources/xdag-testnet.config index ab9ae0b8..702cffcf 100644 --- a/src/main/resources/xdag-testnet.config +++ b/src/main/resources/xdag-testnet.config @@ -36,3 +36,6 @@ whiteIPs = bootnode = enr:-Iu4QPY6bYDC0PaafEwhgg_6yTcx0GAGbSARYqehJKEkyOmxX6SNZMyMMdkmDw9bAvYN9m2LrqIsPSd-bUqff0tsHYABgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQJ2EWgMpl6PtyFKMbbOb82Ob-al9NeE3GYB3-K7n4yWwoN0Y3CCJxGDdWRwgicR isRPCEnabled = true +rpcHost = 127.0.0.1 +rpcPort_http = 4444 +rpcPort_ws = 4445 From 69779c287b4c906cb14e742ef3ead6af96e969a0 Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 22:29:58 +0800 Subject: [PATCH 10/11] add a temp doc for rpc --- docs/XDAGJ_RPCService.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/XDAGJ_RPCService.md diff --git a/docs/XDAGJ_RPCService.md b/docs/XDAGJ_RPCService.md new file mode 100644 index 00000000..1668ebcb --- /dev/null +++ b/docs/XDAGJ_RPCService.md @@ -0,0 +1,18 @@ +# XDAGJ RPC Service Tutorial + +This section describes XDAGJ RPC service. + +If you want to open the rpc service,you need to set "isRPCEnabled = true" in your xdag-XXX.config. + +## Usage + +```js +curl http://localhost:4444/ -s -X POST -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"xdag_syncing\",\"params\":[],\"id\":1}" +``` + +```json +{"jsonrpc":"2.0","id":1,"result":{"currentBlock":"0x30331","highestBlock":"0x30331"}} +``` + + + From 8d17f311b8eec0e50a18a0f527deae79b86b868c Mon Sep 17 00:00:00 2001 From: punk8 <1401501690@qq.com> Date: Mon, 31 May 2021 22:46:30 +0800 Subject: [PATCH 11/11] add rpc doc --- docs/XDAGJ_RPCService.md | 18 ---------------- docs/XdagJ_RPC_Service_end.md | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 18 deletions(-) delete mode 100644 docs/XDAGJ_RPCService.md create mode 100644 docs/XdagJ_RPC_Service_end.md diff --git a/docs/XDAGJ_RPCService.md b/docs/XDAGJ_RPCService.md deleted file mode 100644 index 1668ebcb..00000000 --- a/docs/XDAGJ_RPCService.md +++ /dev/null @@ -1,18 +0,0 @@ -# XDAGJ RPC Service Tutorial - -This section describes XDAGJ RPC service. - -If you want to open the rpc service,you need to set "isRPCEnabled = true" in your xdag-XXX.config. - -## Usage - -```js -curl http://localhost:4444/ -s -X POST -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"xdag_syncing\",\"params\":[],\"id\":1}" -``` - -```json -{"jsonrpc":"2.0","id":1,"result":{"currentBlock":"0x30331","highestBlock":"0x30331"}} -``` - - - diff --git a/docs/XdagJ_RPC_Service_end.md b/docs/XdagJ_RPC_Service_end.md new file mode 100644 index 00000000..4612307a --- /dev/null +++ b/docs/XdagJ_RPC_Service_end.md @@ -0,0 +1,39 @@ +# XDAGJ RPC Service Tutorial + +This section describes XDAGJ RPC service. + +- [System environment](#system-environment) +- [Usage](#usage) + +## System environment + +```yaml + JDK : v15 + script : xdag.sh + jar : xdagj-0.x.y-shaded.jar +``` + + Please make sure that the above environment is already available in your operating system, and the JDK version must be 15 + + +## Usage + +If you want to open the rpc service,you need to set "isRPCEnabled = true" in your configuration file. + +The configuration file is located in `src/main/resources/xdag-XXX.config`, if you do not modify it, the default configuration is disabled. + +- Show XDAG synchronization status + + request + ```js + curl http://localhost:4444/ -s -X POST -H "Content-Type: application/json" --data "{\"jsonrpc\":\"2.0\",\"method\":\"xdag_syncing\",\"params\":[],\"id\":1}" + ``` + response + ```json + {"jsonrpc":"2.0","id":1,"result":{"currentBlock":"0x30331","highestBlock":"0x30331"}} + ``` + + + + +