diff --git a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/client/BftsmartMessageService.java b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/client/BftsmartMessageService.java
index 53a5f0a8..5ecf6596 100644
--- a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/client/BftsmartMessageService.java
+++ b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/client/BftsmartMessageService.java
@@ -40,7 +40,7 @@ public class BftsmartMessageService implements MessageService {
asyncFuture.complete(result);
} catch (Exception e) {
- throw new RuntimeException();
+ throw new RuntimeException(e);
} finally {
asyncPeerProxyPool.returnObject(asynchServiceProxy);
diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java
index 80be911f..3eac13bb 100644
--- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java
+++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractDeployMojo.java
@@ -5,6 +5,7 @@ import com.jd.blockchain.crypto.PrivKey;
import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.BlockchainKeypair;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
+import com.jd.blockchain.utils.StringUtils;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.io.FileUtils;
import org.apache.maven.plugin.AbstractMojo;
diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/StringUtils.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/StringUtils.java
deleted file mode 100644
index f8fe1867..00000000
--- a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/StringUtils.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.jd.blockchain;
-/**
- * @Author zhaogw
- * @Date 2018/11/26 20:46
- */
-public abstract class StringUtils {
- public static boolean isEmpty(Object str) {
- return str == null || "".equals(str);
- }
-}
\ No newline at end of file
diff --git a/source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties b/source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties
index 6dd66e5e..a7179906 100644
--- a/source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties
+++ b/source/contract/contract-maven-plugin/src/main/resources/sys-contract.properties
@@ -1,9 +1,9 @@
-#项目源文件存放的位置;
+#PROJECT_BASE_DIR
PROJECT_BASE_DIR=E:\\gitCode\\block\\prototype\\
-#合同使用的类库存放的位置,可能不在项目中,故采用全新的地址;
+#LEDGER_BASE_CLASS_PATH
LEDGER_BASE_CLASS_PATH=E:\\gitCode\\block\\prototype\\libs\\
-#为了测试,临时添加的变量;
+#deploy and execute the contract;
cParam=com.jd.blockchain.contract.AssetContract3
sParam=E:\\gitCode\\block\\prototype\\source\\sdk\\contract-sample\\src\\main\\java\\
eParam=utf-8
diff --git a/source/contract/contract-tools/pom.xml b/source/contract/contract-tools/pom.xml
deleted file mode 100644
index da60f463..00000000
--- a/source/contract/contract-tools/pom.xml
+++ /dev/null
@@ -1,80 +0,0 @@
-
- 4.0.0
-
- com.jd.blockchain
- contract
- 0.9.0-SNAPSHOT
-
- contract-tools
-
-
-
- com.jd.blockchain
- contract-compiler
- ${project.version}
-
-
- com.jd.blockchain
- contract-jar
- ${project.version}
-
-
- commons-io
- commons-io
- ${commons-io.version}
-
-
- junit
- junit
- test
-
-
- org.mockito
- mockito-core
- test
-
-
- org.slf4j
- slf4j-log4j12
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.5
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/source/crypto/crypto-adv/pom.xml b/source/crypto/crypto-adv/pom.xml
index bf759175..6c3705f2 100644
--- a/source/crypto/crypto-adv/pom.xml
+++ b/source/crypto/crypto-adv/pom.xml
@@ -21,6 +21,13 @@
org.bouncycastle
bcprov-jdk15on
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.61
+
+
com.jd.blockchain
binary-proto
diff --git a/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java
index 8ace44d1..a88b14ed 100644
--- a/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java
+++ b/source/crypto/crypto-adv/src/test/java/test/com/jd/blockchain/crypto/paillier/PaillierUtilsTest.java
@@ -19,7 +19,7 @@ import static org.junit.Assert.assertEquals;
*/
public class PaillierUtilsTest {
@Test
- public void generateKeyPairTest() {
+ public void test() {
AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
@@ -58,13 +58,6 @@ public class PaillierUtilsTest {
assertEquals(pInverseConverted, pInverse);
assertEquals(muPConverted, muP);
assertEquals(muQConverted, muQ);
- }
-
- @Test
- public void encryptTest() {
-
- AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
- PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
@@ -77,23 +70,15 @@ public class PaillierUtilsTest {
assertEquals(512,ciphertextFromParams.length);
assertEquals(512,ciphertextFromBytes.length);
- }
- @Test
- public void decryptTest(){
- AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
- PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
- PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
-
- byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
byte[] privKeyBytes = PaillierUtils.privKey2Bytes(privKeyParams);
int input = 666;
- byte[] data = intToByteArray(input);
+ byte[] inputBytes = intToByteArray(input);
- byte[] ciphertextFromParams = PaillierUtils.encrypt(data,pubKeyParams);
- byte[] ciphertextFromBytes = PaillierUtils.encrypt(data,pubKeyBytes);
+ ciphertextFromParams = PaillierUtils.encrypt(inputBytes,pubKeyParams);
+ ciphertextFromBytes = PaillierUtils.encrypt(inputBytes,pubKeyBytes);
byte[] plaintextFromParams = PaillierUtils.decrypt(ciphertextFromBytes,privKeyParams);
byte[] plaintextFromBytes = PaillierUtils.decrypt(ciphertextFromParams,privKeyBytes);
@@ -103,16 +88,9 @@ public class PaillierUtilsTest {
assertEquals(input,outputFromParams);
assertEquals(input,outputFromBytes);
- }
- @Test
- public void addTest() {
- AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
- PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
- PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
-
- byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+ pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
int input1 = 600;
int input2 = 60;
@@ -139,26 +117,19 @@ public class PaillierUtilsTest {
output = byteArrayToInt(plaintext);
assertEquals(sum,output);
- }
- @Test
- public void scalarMultiplyTest() {
- AsymmetricCipherKeyPair keyPair = PaillierUtils.generateKeyPair();
- PaillierPublicKeyParameters pubKeyParams = (PaillierPublicKeyParameters) keyPair.getPublic();
- PaillierPrivateKeyParameters privKeyParams = (PaillierPrivateKeyParameters) keyPair.getPrivate();
-
- byte[] pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
+ pubKeyBytes = PaillierUtils.pubKey2Bytes(pubKeyParams);
- int input = 111;
+ input = 111;
int scalar = 6;
- byte[] data = intToByteArray(input);
+ data = intToByteArray(input);
byte[] ciphertext = PaillierUtils.encrypt(data,pubKeyParams);
byte[] ciphertextPowered = PaillierUtils.scalarMultiply(pubKeyBytes,ciphertext,scalar);
byte[] plaintextMultiplied = PaillierUtils.decrypt(ciphertextPowered,privKeyParams);
- int output = byteArrayToInt(plaintextMultiplied);
+ output = byteArrayToInt(plaintextMultiplied);
assertEquals(input * scalar, output);
}
diff --git a/source/crypto/crypto-classic/pom.xml b/source/crypto/crypto-classic/pom.xml
index bd59aeb8..75ab597b 100644
--- a/source/crypto/crypto-classic/pom.xml
+++ b/source/crypto/crypto-classic/pom.xml
@@ -15,6 +15,12 @@
crypto-framework
${project.version}
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.61
+
\ No newline at end of file
diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java
index b7bd9c8d..ab078bfb 100644
--- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java
+++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/RSACryptoFunction.java
@@ -21,11 +21,11 @@ public class RSACryptoFunction implements AsymmetricEncryptionFunction, Signatur
private static final CryptoAlgorithm RSA = ClassicAlgorithm.RSA;
- // modulus.length = 256, publicExponent.length = 1
- private static final int PUBKEY_SIZE = 257;
- // modulus.length = 256, publicExponent.length = 1, privateExponent.length = 256, p.length = 128, q.length =128,
+ // modulus.length = 256, publicExponent.length = 3
+ private static final int PUBKEY_SIZE = 259;
+ // modulus.length = 256, publicExponent.length = 3, privateExponent.length = 256, p.length = 128, q.length =128,
// dP.length = 128, dQ.length = 128, qInv.length = 128
- private static final int PRIVKEY_SIZE = 1153;
+ private static final int PRIVKEY_SIZE = 1155;
private static final int SIGNATUREDIGEST_SIZE = 256;
private static final int CIPHERTEXTBLOCK_SIZE = 256;
diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java
index 555f5006..a787b655 100644
--- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java
+++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/RSAUtils.java
@@ -60,6 +60,7 @@ public class RSAUtils {
private static final int QINV_LENGTH = 1024 / 8;
private static final BigInteger PUBEXP_0X03 = BigInteger.valueOf(0x03);
+ private static final BigInteger PUBEXP_0X010001 = BigInteger.valueOf(0x010001);
private static final BigInteger VERSION_2PRIMES = BigInteger.valueOf(0);
@@ -82,6 +83,21 @@ public class RSAUtils {
}
public static AsymmetricCipherKeyPair generateKeyPair(SecureRandom random){
+ AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator();
+ kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X010001, random, KEYSIZEBITS, CERTAINTY));
+ return kpGen.generateKeyPair();
+ }
+
+ /**
+ * key pair generation with short public exponent锛 resulting in verifying and encrypting more efficiently
+ *
+ * @return key pair
+ */
+ public static AsymmetricCipherKeyPair generateKeyPair_shortExp(){
+ return generateKeyPair_shortExp(new SecureRandom());
+ }
+
+ public static AsymmetricCipherKeyPair generateKeyPair_shortExp(SecureRandom random){
AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator();
kpGen.init(new RSAKeyGenerationParameters(PUBEXP_0X03, random, KEYSIZEBITS, CERTAINTY));
return kpGen.generateKeyPair();
@@ -303,22 +319,16 @@ public class RSAUtils {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKeyBytes);
- KeyFactory keyFactory = null;
- try {
- keyFactory = KeyFactory.getInstance("RSA");
- } catch (NoSuchAlgorithmException e) {
- throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e);
- }
+ KeyFactory keyFactory;
+ RSAPublicKey publicKey;
- RSAPublicKey publicKey = null;
try {
+ keyFactory = KeyFactory.getInstance("RSA");
publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
- } catch (InvalidKeySpecException e) {
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e);
}
- assert publicKey != null;
-
BigInteger exponent = publicKey.getPublicExponent();
BigInteger modulus = publicKey.getModulus();
@@ -414,7 +424,7 @@ public class RSAUtils {
BigInteger qInv = privKey.getQInv();
byte[] modulusBytes = bigInteger2Bytes(modulus,MODULUS_LENGTH);
- byte[] pubExpBytes = pubExp.toByteArray();
+ byte[] pubExpBytes = pubExp.toByteArray();
byte[] privExpBytes = bigInteger2Bytes(privExp,PRIVEXP_LENGTH);
byte[] pBytes = bigInteger2Bytes(p,P_LENGTH);
byte[] qBytes = bigInteger2Bytes(q,Q_LENGTH);
@@ -446,22 +456,16 @@ public class RSAUtils {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKeyBytes);
- KeyFactory keyFactory = null;
- try {
- keyFactory = KeyFactory.getInstance("RSA");
- } catch (NoSuchAlgorithmException e) {
- throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e);
- }
-
+ KeyFactory keyFactory;
RSAPrivateCrtKey privateKey;
+
try {
+ keyFactory = KeyFactory.getInstance("RSA");
privateKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
- } catch (InvalidKeySpecException e) {
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new com.jd.blockchain.crypto.CryptoException(e.getMessage(), e);
}
- assert privateKey != null;
-
BigInteger modulus = privateKey.getModulus();
BigInteger pubExp = privateKey.getPublicExponent();
BigInteger privExp = privateKey.getPrivateExponent();
@@ -524,7 +528,7 @@ public class RSAUtils {
result,0, length);
} else {
System.arraycopy(srcBytes,0,
- result,length - srcLength, length);
+ result,length - srcLength, srcLength);
}
return result;
diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SSHKeyParser.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SSHKeyParser.java
new file mode 100644
index 00000000..73e5243a
--- /dev/null
+++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/utils/classic/SSHKeyParser.java
@@ -0,0 +1,49 @@
+package com.jd.blockchain.crypto.utils.classic;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec;
+import org.bouncycastle.util.encoders.Base64;
+
+/**
+ * @author zhanglin33
+ * @title: SSHKeyParser
+ * @description: a parser for parsing asymmetric keys in Base64 format
+ * @date 2019-05-17, 17:52
+ */
+public class SSHKeyParser {
+
+ private String pubKeyFormat;
+ private String pubKeyType;
+
+ public AsymmetricKeyParameter pubKeyParse(String pubKeyStr) {
+
+ byte[] pubKeyBytes;
+
+ if (pubKeyStr.startsWith("ssh") || pubKeyStr.startsWith("ecdsa")) {
+ String[] algoAndKeyAndLocal = pubKeyStr.split(" ");
+ pubKeyBytes = Base64.decode(algoAndKeyAndLocal[1]);
+ } else {
+ pubKeyBytes = Base64.decode(pubKeyStr);
+ }
+
+ OpenSSHPublicKeySpec pubKeySpec = new OpenSSHPublicKeySpec(pubKeyBytes);
+
+ pubKeyFormat = pubKeySpec.getFormat();
+ pubKeyType = pubKeySpec.getType();
+
+ return OpenSSHPublicKeyUtil.parsePublicKey(pubKeyBytes);
+ }
+
+
+
+
+
+ public String getPubKeyFormat() {
+ return pubKeyFormat;
+ }
+
+ public String getPubKeyType() {
+ return pubKeyType;
+ }
+}
diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java
index bb61d80b..60f4d113 100644
--- a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java
+++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/RSACryptoFunctionTest.java
@@ -42,7 +42,7 @@ public class RSACryptoFunctionTest {
}
@Test
- public void generateKeyPairTest() {
+ public void test() {
CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
assertNotNull(algorithm);
@@ -55,15 +55,15 @@ public class RSACryptoFunctionTest {
PrivKey privKey = keyPair.getPrivKey();
assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE);
- assertEquals(257, pubKey.getRawKeyBytes().length);
+ assertEquals(259, pubKey.getRawKeyBytes().length);
assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE);
- assertEquals(1153, privKey.getRawKeyBytes().length);
+ assertEquals(1155, privKey.getRawKeyBytes().length);
assertEquals(algorithm.code(), pubKey.getAlgorithm());
assertEquals(algorithm.code(), privKey.getAlgorithm());
- assertEquals(2 + 1 + 257, pubKey.toBytes().length);
- assertEquals(2 + 1 + 1153, privKey.toBytes().length);
+ assertEquals(2 + 1 + 259, pubKey.toBytes().length);
+ assertEquals(2 + 1 + 1155, privKey.toBytes().length);
byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
@@ -72,20 +72,7 @@ public class RSACryptoFunctionTest {
byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes());
assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes());
- }
-
- @Test
- public void retrievePubKeyTest() {
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
- PrivKey privKey = keyPair.getPrivKey();
PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey);
@@ -93,23 +80,12 @@ public class RSACryptoFunctionTest {
assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length);
assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm());
assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes());
- }
- @Test
- public void signTest() {
- byte[] data = new byte[1024];
+ byte[] data = new byte[128];
Random random = new Random();
random.nextBytes(data);
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PrivKey privKey = keyPair.getPrivKey();
SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
byte[] signatureBytes = signatureDigest.toBytes();
@@ -121,48 +97,16 @@ public class RSACryptoFunctionTest {
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)),
signatureDigest.getAlgorithm());
- byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm());
byte[] rawSinatureBytes = signatureDigest.getRawDigest();
assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes);
- }
- @Test
- public void verifyTest() {
- byte[] data = new byte[1024];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
- PrivKey privKey = keyPair.getPrivKey();
- SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
assertTrue(signatureFunction.verify(signatureDigest, pubKey, data));
- }
-
- @Test
- public void encryptTest() {
-
- byte[] data = new byte[128];
- Random random = new Random();
- random.nextBytes(data);
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto
.getAsymmetricEncryptionFunction(algorithm);
- AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
-
Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data);
byte[] ciphertextBytes = ciphertext.toBytes();
@@ -172,90 +116,32 @@ public class RSACryptoFunctionTest {
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)),
ciphertext.getAlgorithm());
- byte[] algoBytes = BytesUtils.toBytes(ciphertext.getAlgorithm());
byte[] rawCiphertextBytes = ciphertext.getRawCiphertext();
assertArrayEquals(BytesUtils.concat(algoBytes, rawCiphertextBytes), ciphertextBytes);
- }
- @Test
- public void decryptTest() {
-
- byte[] data = new byte[128];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto
- .getAsymmetricEncryptionFunction(algorithm);
-
- AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
- PrivKey privKey = keyPair.getPrivKey();
-
- Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data);
byte[] decryptedPlaintext = asymmetricEncryptionFunction.decrypt(privKey, ciphertext);
-
assertArrayEquals(data, decryptedPlaintext);
- }
-
- @Test
- public void supportPrivKeyTest() {
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
- PrivKey privKey = keyPair.getPrivKey();
byte[] privKeyBytes = privKey.toBytes();
-
assertTrue(signatureFunction.supportPrivKey(privKeyBytes));
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
byte[] rawKeyBytes = privKey.getRawKeyBytes();
byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes);
-
assertFalse(signatureFunction.supportPrivKey(ripemd160PubKeyBytes));
- }
- @Test
- public void resolvePrivKeyTest() {
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PrivKey privKey = keyPair.getPrivKey();
- byte[] privKeyBytes = privKey.toBytes();
PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes);
-
assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE);
- assertEquals(1153, resolvedPrivKey.getRawKeyBytes().length);
+ assertEquals(1155, resolvedPrivKey.getRawKeyBytes().length);
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPrivKey.getAlgorithm());
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)),
resolvedPrivKey.getAlgorithm());
assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes());
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
- byte[] rawKeyBytes = privKey.getRawKeyBytes();
- byte[] ripemd160PubKeyBytes = BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawKeyBytes);
-
Class> expectedException = CryptoException.class;
Exception actualEx = null;
try {
@@ -265,64 +151,26 @@ public class RSACryptoFunctionTest {
}
assertNotNull(actualEx);
assertTrue(expectedException.isAssignableFrom(actualEx.getClass()));
- }
-
- @Test
- public void supportPubKeyTest() {
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
byte[] pubKeyBytes = pubKey.toBytes();
-
assertTrue(signatureFunction.supportPubKey(pubKeyBytes));
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE };
- byte[] rawKeyBytes = pubKey.getRawKeyBytes();
byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes);
-
assertFalse(signatureFunction.supportPubKey(ripemd160PrivKeyBytes));
- }
-
- @Test
- public void resolvePubKeyTest() {
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
- PubKey pubKey = keyPair.getPubKey();
- byte[] pubKeyBytes = pubKey.toBytes();
PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes);
-
assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE);
- assertEquals(257, resolvedPubKey.getRawKeyBytes().length);
+ assertEquals(259, resolvedPubKey.getRawKeyBytes().length);
assertEquals(ClassicAlgorithm.RSA.code(), resolvedPubKey.getAlgorithm());
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)),
resolvedPubKey.getAlgorithm());
assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes());
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE };
- byte[] rawKeyBytes = pubKey.getRawKeyBytes();
- byte[] ripemd160PrivKeyBytes = BytesUtils.concat(algoBytes, privKeyTypeBytes, rawKeyBytes);
-
- Class> expectedException = CryptoException.class;
- Exception actualEx = null;
try {
signatureFunction.resolvePrivKey(ripemd160PrivKeyBytes);
} catch (Exception e) {
@@ -330,57 +178,18 @@ public class RSACryptoFunctionTest {
}
assertNotNull(actualEx);
assertTrue(expectedException.isAssignableFrom(actualEx.getClass()));
- }
-
- @Test
- public void supportDigestTest() {
-
- byte[] data = new byte[1024];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PrivKey privKey = keyPair.getPrivKey();
-
- SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
byte[] signatureDigestBytes = signatureDigest.toBytes();
assertTrue(signatureFunction.supportDigest(signatureDigestBytes));
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
byte[] rawDigestBytes = signatureDigest.toBytes();
byte[] ripemd160SignatureBytes = BytesUtils.concat(algoBytes, rawDigestBytes);
assertFalse(signatureFunction.supportDigest(ripemd160SignatureBytes));
- }
-
- @Test
- public void resolveDigestTest() {
-
- byte[] data = new byte[1024];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
-
- AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
-
- PrivKey privKey = keyPair.getPrivKey();
- SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
-
- byte[] signatureDigestBytes = signatureDigest.toBytes();
SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes);
@@ -392,12 +201,8 @@ public class RSACryptoFunctionTest {
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] rawDigestBytes = signatureDigest.getRawDigest();
byte[] ripemd160SignatureDigestBytes = BytesUtils.concat(algoBytes, rawDigestBytes);
- Class> expectedException = CryptoException.class;
- Exception actualEx = null;
try {
signatureFunction.resolveDigest(ripemd160SignatureDigestBytes);
} catch (Exception e) {
@@ -405,77 +210,24 @@ public class RSACryptoFunctionTest {
}
assertNotNull(actualEx);
assertTrue(expectedException.isAssignableFrom(actualEx.getClass()));
- }
-
- @Test
- public void supportCiphertextTest() {
-
- byte[] data = new byte[128];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto
- .getAsymmetricEncryptionFunction(algorithm);
-
- AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair();
-
- PubKey pubKey = keyPair.getPubKey();
-
- Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data);
- byte[] ciphertextBytes = ciphertext.toBytes();
assertTrue(asymmetricEncryptionFunction.supportCiphertext(ciphertextBytes));
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] rawCiphertextBytes = ciphertext.toBytes();
+ algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes);
-
assertFalse(asymmetricEncryptionFunction.supportCiphertext(ripemd160CiphertextBytes));
- }
-
- @Test
- public void resolveCiphertextTest() {
-
- byte[] data = new byte[128];
- Random random = new Random();
- random.nextBytes(data);
-
- CryptoAlgorithm algorithm = Crypto.getAlgorithm("RSA");
- assertNotNull(algorithm);
-
- AsymmetricEncryptionFunction asymmetricEncryptionFunction = Crypto
- .getAsymmetricEncryptionFunction(algorithm);
-
- AsymmetricKeypair keyPair = asymmetricEncryptionFunction.generateKeypair();
- PubKey pubKey = keyPair.getPubKey();
-
- Ciphertext ciphertext = asymmetricEncryptionFunction.encrypt(pubKey, data);
-
- byte[] ciphertextBytes = ciphertext.toBytes();
Ciphertext resolvedCiphertext = asymmetricEncryptionFunction.resolveCiphertext(ciphertextBytes);
-
assertEquals(256, resolvedCiphertext.getRawCiphertext().length);
assertEquals(ClassicAlgorithm.RSA.code(), resolvedCiphertext.getAlgorithm());
assertEquals((short) (SIGNATURE_ALGORITHM | ENCRYPTION_ALGORITHM | ASYMMETRIC_KEY | ((byte) 23 & 0x00FF)),
resolvedCiphertext.getAlgorithm());
assertArrayEquals(ciphertextBytes, resolvedCiphertext.toBytes());
-
algorithm = Crypto.getAlgorithm("ripemd160");
assertNotNull(algorithm);
- byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
- byte[] rawCiphertextBytes = ciphertext.getRawCiphertext();
- byte[] ripemd160CiphertextBytes = BytesUtils.concat(algoBytes, rawCiphertextBytes);
-
- Class> expectedException = CryptoException.class;
- Exception actualEx = null;
try {
asymmetricEncryptionFunction.resolveCiphertext(ripemd160CiphertextBytes);
} catch (Exception e) {
@@ -484,5 +236,4 @@ public class RSACryptoFunctionTest {
assertNotNull(actualEx);
assertTrue(expectedException.isAssignableFrom(actualEx.getClass()));
}
-
}
diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java
index c8497d7e..a8c82e85 100644
--- a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java
+++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/RSAUtilsTest.java
@@ -1,16 +1,22 @@
package test.com.jd.blockchain.crypto.utils.classic;
import com.jd.blockchain.crypto.utils.classic.RSAUtils;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
@@ -27,10 +33,20 @@ import static org.junit.Assert.*;
public class RSAUtilsTest {
@Test
- public void generateKeyPairTest(){
+ public void generateKeyPairTest() {
AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair();
- RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic();
- RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) kp.getPrivate();
+ keyPairTest(kp);
+ }
+
+ @Test
+ public void generateKeyPair_ShortExpTest() {
+ AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair_shortExp();
+ keyPairTest(kp);
+ }
+
+ private void keyPairTest(AsymmetricCipherKeyPair keyPair) {
+ RSAKeyParameters pubKey = (RSAKeyParameters) keyPair.getPublic();
+ RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();
byte[] pubKeyBytes_RawKey = RSAUtils.pubKey2Bytes_RawKey(pubKey);
byte[] pubKeyBytesConverted_RawKey =
@@ -42,9 +58,6 @@ public class RSAUtilsTest {
RSAUtils.privKey2Bytes_RawKey(RSAUtils.bytes2PrivKey_RawKey(privKeyBytes_RawKey));
assertArrayEquals(privKeyBytes_RawKey,privKeyBytesConverted_RawKey);
- System.out.println(pubKeyBytes_RawKey.length);
- System.out.println(privKeyBytes_RawKey.length);
-
byte[] pubKeyBytes_PKCS1 = RSAUtils.pubKey2Bytes_PKCS1(pubKey);
byte[] pubKeyBytesConverted_PKCS1 =
RSAUtils.pubKey2Bytes_PKCS1(RSAUtils.bytes2PubKey_PKCS1(pubKeyBytes_PKCS1));
@@ -67,7 +80,7 @@ public class RSAUtilsTest {
}
@Test
- public void retrievePublicKeyTest(){
+ public void test(){
AsymmetricCipherKeyPair kp = RSAUtils.generateKeyPair();
RSAKeyParameters pubKey = (RSAKeyParameters) kp.getPublic();
@@ -78,38 +91,17 @@ public class RSAUtilsTest {
byte[] retrievedPubKeyBytes = RSAUtils.retrievePublicKey(privKeyBytes);
assertArrayEquals(pubKeyBytes,retrievedPubKeyBytes);
- }
-
- @Test
- public void signTest(){
- byte[] data = new byte[1024];
+ byte[] data = new byte[128];
Random random = new Random();
random.nextBytes(data);
- AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair();
- AsymmetricKeyParameter privKey = keyPair.getPrivate();
- byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey);
-
byte[] signatureFromPrivKey = RSAUtils.sign(data, privKey);
byte[] signatureFromPrivKeyBytes = RSAUtils.sign(data, privKeyBytes);
assertNotNull(signatureFromPrivKey);
assertEquals(2048 / 8, signatureFromPrivKey.length);
assertArrayEquals(signatureFromPrivKeyBytes,signatureFromPrivKey);
- }
-
- @Test
- public void verifyTest(){
-
- byte[] data = new byte[1024];
- Random random = new Random();
- random.nextBytes(data);
-
- AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair();
- AsymmetricKeyParameter privKey = keyPair.getPrivate();
- AsymmetricKeyParameter pubKey = keyPair.getPublic();
- byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey);
byte[] signature = RSAUtils.sign(data,privKey);
@@ -118,47 +110,23 @@ public class RSAUtilsTest {
assertTrue(isValidFromPubKey);
assertTrue(isValidFromPubKeyBytes);
- }
-
- @Test
- public void encryptTest(){
-
- byte[] data = new byte[246];
- Random random = new Random();
- random.nextBytes(data);
-
- AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair();
- AsymmetricKeyParameter pubKey = keyPair.getPublic();
- byte[] pubKeyBytes = RSAUtils.pubKey2Bytes_RawKey((RSAKeyParameters) pubKey);
byte[] ciphertextFromPubKey = RSAUtils.encrypt(data,pubKey);
byte[] ciphertextFromPubKeyBytes = RSAUtils.encrypt(data,pubKeyBytes);
- assertEquals(512,ciphertextFromPubKey.length);
- assertEquals(512,ciphertextFromPubKeyBytes.length);
- }
-
- @Test
- public void decryptTest(){
+ assertEquals(256,ciphertextFromPubKey.length);
+ assertEquals(256,ciphertextFromPubKeyBytes.length);
- AsymmetricCipherKeyPair keyPair = RSAUtils.generateKeyPair();
- AsymmetricKeyParameter pubKey = keyPair.getPublic();
- AsymmetricKeyParameter privKey = keyPair.getPrivate();
- byte[] privKeyBytes = RSAUtils.privKey2Bytes_RawKey((RSAPrivateCrtKeyParameters) privKey);
- byte[] data;
- for (int i = 1; i < 1024; i++) {
- data = new byte[i];
- Random random = new Random();
- random.nextBytes(data);
- byte[] ciphertext = RSAUtils.encrypt(data, pubKey);
+ data = new byte[1024];
+ random.nextBytes(data);
+ byte[] ciphertext = RSAUtils.encrypt(data, pubKey);
- byte[] plaintextFromPrivKey = RSAUtils.decrypt(ciphertext, privKey);
- byte[] plaintextFromPrivKeyBytes = RSAUtils.decrypt(ciphertext, privKeyBytes);
+ byte[] plaintextFromPrivKey = RSAUtils.decrypt(ciphertext, privKey);
+ byte[] plaintextFromPrivKeyBytes = RSAUtils.decrypt(ciphertext, privKeyBytes);
- assertArrayEquals(data, plaintextFromPrivKey);
- assertArrayEquals(data, plaintextFromPrivKeyBytes);
- }
+ assertArrayEquals(data, plaintextFromPrivKey);
+ assertArrayEquals(data, plaintextFromPrivKeyBytes);
}
diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/SSHKeyUtilsTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/SSHKeyUtilsTest.java
new file mode 100644
index 00000000..a873ed78
--- /dev/null
+++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/utils/classic/SSHKeyUtilsTest.java
@@ -0,0 +1,231 @@
+//package test.com.jd.blockchain.crypto.utils.classic;
+//
+//import com.jd.blockchain.crypto.utils.classic.SSHKeyParser;
+//import org.bouncycastle.asn1.ASN1Sequence;
+//import org.bouncycastle.crypto.params.RSAKeyParameters;
+//import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+//import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
+//import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+//import org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec;
+//import org.bouncycastle.jce.spec.OpenSSHPublicKeySpec;
+//import org.bouncycastle.util.Strings;
+//import org.bouncycastle.util.encoders.Base64;
+//import org.bouncycastle.util.encoders.Hex;
+//import org.bouncycastle.util.io.pem.PemReader;
+//import org.junit.Test;
+//
+//import java.io.IOException;
+//import java.io.StringReader;
+//import java.math.BigInteger;
+//
+//import static org.junit.Assert.assertEquals;
+//
+///**
+// * @author zhanglin33
+// * @title: SSHKeyUtilsTest
+// * @description: Tests for methods in SSHKeyUtils
+// * @date 2019-05-07, 15:14
+// */
+//public class SSHKeyUtilsTest {
+//
+// @Test
+// public void parseRSAPublicKeyTest() {
+//
+// String pubKeyStr = "AAAAB3NzaC1yc2EAAAADAQABAAABAQCYwLN4EXy7g0Xugv4lQfoujbARi48gPSxVupt" +
+// "GsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkcdNhGWZmPnopV+D46CTFB1" +
+// "4yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT5bXqP/4gXkLENEU5tLsWVAOu0ME/N" +
+// "e/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvBuiL7WBXxDJ/IASJrKNGBdK8xib1+Kb8tNLAT6" +
+// "Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRVD6CJ";
+//
+// BigInteger exponent = new BigInteger("010001",16);
+// BigInteger modulus = new BigInteger("0098c0b378117cbb8345ee82fe2541fa2e8db0118b8f2" +
+// "03d2c55ba9b46b12a06aac4b4d1ef6b03bbf4ab314a6bd6619f0d569230a711745800c88200962" +
+// "433f98623c99bdea91c74d84659998f9e8a55f83e3a093141d78c9e47d9a3a0e3d7b38a635f7cc" +
+// "6bde2b1e4dc7c8ef76815ec1b4c2b5d374c755d64e3353e5b5ea3ffe205e42c4344539b4bb1654" +
+// "03aed0c13f35effd80cba302d0e8a25275f356bd3f4e9bbc4a48c3970bb549ec9b90adbc1ba22f" +
+// "b5815f10c9fc801226b28d18174af3189bd7e29bf2d34b013e838f6e41c3296a8913616f997536" +
+// "2e1a2ab13616a484739371e7e72c40c125f4c049de912c2c704d6e88432fe8dbc0b82e4550fa089",16);
+// String pubKeyFormat = "OpenSSH";
+// String pubKeyType = "ssh-rsa";
+//
+// SSHKeyParser parser = new SSHKeyParser();
+//
+// RSAKeyParameters pubKey = (RSAKeyParameters) parser.pubKeyParse(pubKeyStr);
+// BigInteger e = pubKey.getExponent();
+// BigInteger n = pubKey.getModulus();
+// assertEquals(exponent,e);
+// assertEquals(modulus,n);
+// assertEquals(pubKeyFormat,parser.getPubKeyFormat());
+// assertEquals(pubKeyType,parser.getPubKeyType());
+//
+// String pubKeyStrWithHead = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCYwLN4EXy7g0Xugv4lQfou" +
+// "jbARi48gPSxVuptGsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkcdNhGWZm" +
+// "PnopV+D46CTFB14yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT5bXqP/4gXkLENEU5" +
+// "tLsWVAOu0ME/Ne/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvBuiL7WBXxDJ/IASJrKNGBdK8xi" +
+// "b1+Kb8tNLAT6Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRV" +
+// "D6CJ zhanglin33@zhanglin33.local\n";
+// pubKey = (RSAKeyParameters) parser.pubKeyParse(pubKeyStrWithHead);
+// e = pubKey.getExponent();
+// n = pubKey.getModulus();
+// assertEquals(exponent,e);
+// assertEquals(modulus,n);
+// assertEquals(pubKeyFormat,parser.getPubKeyFormat());
+// assertEquals(pubKeyType,parser.getPubKeyType());
+// }
+//
+// @Test
+// public void parseRSAPrivateKeyTest() {
+//
+// String str2 = "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
+// "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" +
+// "NhAAAAAwEAAQAAAQEAwFyeWgHFu/ZMvqWa28QUGlKMDV7vpbzT7kyA/4yuotfprZKHNeEy\n" +
+// "GugleJ/Kv5kqHh8Km4IZcfNcerTYds+U5m/uX4bSYpEbXco3DQ2lYQbYo7PBWwPMq2aIdd\n" +
+// "i7WxUAlt0z1ugLNimskPzJ7DNra+ax0Wh9RnMsjZkfuBZiKq7wbBm7NyJmpg2B7xo5cz+G\n" +
+// "Lw9e0tDlvgeLe+n68WvYWWFP59mfP6Qoy+NwjQnnwrhJi2j4dEexO97KmgnJhL07lu4eCQ\n" +
+// "fdv68Tai9+aeDNawe7nmFYf2eNjah2jW/DwOwA/ErXnvgjLSMsgc6WGKfokhytAOFDGgvH\n" +
+// "KKNd6BMYZwAAA9A7JircOyYq3AAAAAdzc2gtcnNhAAABAQDAXJ5aAcW79ky+pZrbxBQaUo\n" +
+// "wNXu+lvNPuTID/jK6i1+mtkoc14TIa6CV4n8q/mSoeHwqbghlx81x6tNh2z5Tmb+5fhtJi\n" +
+// "kRtdyjcNDaVhBtijs8FbA8yrZoh12LtbFQCW3TPW6As2KayQ/MnsM2tr5rHRaH1GcyyNmR\n" +
+// "+4FmIqrvBsGbs3ImamDYHvGjlzP4YvD17S0OW+B4t76frxa9hZYU/n2Z8/pCjL43CNCefC\n" +
+// "uEmLaPh0R7E73sqaCcmEvTuW7h4JB92/rxNqL35p4M1rB7ueYVh/Z42NqHaNb8PA7AD8St\n" +
+// "ee+CMtIyyBzpYYp+iSHK0A4UMaC8coo13oExhnAAAAAwEAAQAAAQAEEvIXnen+LR06/G7n\n" +
+// "MKPsWss0jUouDG3AokYpI2WfdUsxreTHM1nIUBpbD6dPn4LQ2H91A7BeRXUz9BiRi5vvtX\n" +
+// "cq9sQF6mTV+65mzF8wSuDTtr7lmpL/HlDNjiWJrEwy5cRvTMLQBtnsyC3OntgrlNs3QCtH\n" +
+// "DrFm3lNZpr+1f62Vu43dbcTPvLwcc335cJ73BU5WsMGaouCAqVXsVsgfkA66u6+gQs8O3F\n" +
+// "IQntdzS8vYpkzH8N9qqNZit7kbFCRUTI7CDLHquJmclzB8uVwO0pR5+Aross+YL3QxPZoJ\n" +
+// "+LXLlCi27oSmYk3fx3uh0XwwO3JFDQpeCxOuEsZbOy8BAAAAgCsktFksS0BViRuLyzC2H7\n" +
+// "X7Uonf+dr8e4Yn+RgR329KFh/ok28/KZndZHsUnhdmiIjPr+SplFZZMrV/uJDkGezUNWGf\n" +
+// "8qn+eEglm7nYfVf2EXTVNhpg8yfPChx90ybc8GYlqpEqf7LiCuEBCPqPJgq6K7i6UKbwn2\n" +
+// "SfqUOBcz5BAAAAgQDqszdiNv0cTvZ/Xg3qJPsHXqQuLBYoe2vhU+Pipt9HviruUD1y3Mso\n" +
+// "rOL9QBwjE7szGnwVE00J0mLp+s309+kftADLXqMyqFYiy7S8GIWQw0YNB2m8yjq+phHbBm\n" +
+// "/Gs2P4+s8yKTcVJvMTyWr02rpCHiLTKDHoXPJcJ8yVMTHFRwAAAIEA0dHB9fXiesEKfwcp\n" +
+// "X11IHAV8pTd+7VN81oGwxtRg88U7H2rmQFCxSZah2O/OCCmYLH3PHT95qnMHHqzcsVvoIy\n" +
+// "7AfnMpp4KYU0Ic3aFuRjZk2sDsYUniPcCpuCvs8Jb75sDwKDW2EM8MowiNylDnYMmfYj0l\n" +
+// "gIhz1/p79hXEI+EAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" +
+// "-----END OPENSSH PRIVATE KEY-----";
+//
+// byte[] Bytes2 = null;
+// try {
+// Bytes2 = new PemReader(new StringReader(str2)).readPemObject().getContent();
+// } catch (IOException e1) {
+// e1.printStackTrace();
+// }
+// assert Bytes2 != null;
+// System.out.println(Hex.toHexString(Bytes2));
+//
+// String str3 = "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
+// "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" +
+// "NhAAAAAwEAAQAAAQEAvummQZm1FUFc/cV5nQBeowhjX4vIU4kBmyPmXHMViX4ORvWvD1yi\n" +
+// "oxcaawPpP9QconpzjdCrNbmw0oZNt9UKlmrOU34YTRD5LFlEVOYjr/21/SO5yDGog8xJBU\n" +
+// "HQYnXY5L2q9EXKOF45e5P6gSGUovrhePEsaniuQN48GIObPCOFkEN0ZV2DqRsn3It1vY+D\n" +
+// "GiSb5EaZ2sNkudyzYfgFxcCbqBXmDa1WeyX5xYh8wldBJLUH+pO4gPoTXXX4UI4yNdDmPD\n" +
+// "BWFvPVIOdpfdBnDbEp1AoE5Jx/+tbwFBIEvTPOECtOUKDGIlXXIH0I4waHbwf6EnHD5+BR\n" +
+// "N0XwrzSkuwAAA9DYV/7H2Ff+xwAAAAdzc2gtcnNhAAABAQC+6aZBmbUVQVz9xXmdAF6jCG\n" +
+// "Nfi8hTiQGbI+ZccxWJfg5G9a8PXKKjFxprA+k/1ByienON0Ks1ubDShk231QqWas5TfhhN\n" +
+// "EPksWURU5iOv/bX9I7nIMaiDzEkFQdBiddjkvar0Rco4Xjl7k/qBIZSi+uF48SxqeK5A3j\n" +
+// "wYg5s8I4WQQ3RlXYOpGyfci3W9j4MaJJvkRpnaw2S53LNh+AXFwJuoFeYNrVZ7JfnFiHzC\n" +
+// "V0EktQf6k7iA+hNddfhQjjI10OY8MFYW89Ug52l90GcNsSnUCgTknH/61vAUEgS9M84QK0\n" +
+// "5QoMYiVdcgfQjjBodvB/oSccPn4FE3RfCvNKS7AAAAAwEAAQAAAQArRruxUy6BSvfRbtpK\n" +
+// "hLLvMg+UsRMQHJaInHKzskLHkBOcckTkrpMPdUU/zPsqxOJY0nkvRIYK/7TdhCRJ77ker8\n" +
+// "dllcfccGSLcRDUTfb5BgIjB94tS1Rvy/chgfHC4APyliwSg197t6BAKyM18m7HIyfJSqJO\n" +
+// "4FxfyADHbc3aq654tu+eaUtD7TEN1bH6PKMDvwSioMLgKU43GQeDJZbqamBE9y+KVhVx9y\n" +
+// "3DEHrOPkRkZIG33y9j7B/i0vl+WnwUTzmLGRR0U6J9wrzyANL8ODYaAvk4FvUED8hQ72jh\n" +
+// "NpAXsSgf6COUE1sUnO5DOwN1zHBNHaSo73Qu7aKZtL4BAAAAgDBW3ItiqU9Ip34KtLaayK\n" +
+// "/BkRDDwFNvAxpOw9alpfbLGF5xbVjRN4wy7HJ4eA+7JJnx6A6xYrzykbPP+dnUnfzYuxH8\n" +
+// "MrihOkYipw1VaR6/0XH+apmE1SmotuYbl+bpl9dlZYUI0pJ8wldqoDCNlSOcLy77HnKwu9\n" +
+// "GpJx9KmW9WAAAAgQDdnrwfVv5trAuZZIcw2vLRWhoDT196k/Ty1GP4zFpDttb8OyZ8Ygpx\n" +
+// "oA5PhYyl5M1g/2oR/Rpp3vfKDVThfn/bCnMtAbUHMfvYK3Oufvq5JmzT1rgGr3MEek+JBR\n" +
+// "O17I87m4GE7iM1LzCUs2G/fKt2uoVXdniv0Vn0iCiZZc7JmwAAAIEA3IdsccarkUfFcQ2c\n" +
+// "4TdHrx/RGmoTAO6k1xOHXZjWPmerinuOspIJL/ymWfqIxABCjub3UHyP7ap+1+AAnk+TMU\n" +
+// "eR3tLEp9tRM6n0Td56DnQ9Q+RZhPqR486/teZ33cMBMHg52aIs/3AzMpK9xTFCRgqsKa6e\n" +
+// "ednMB4Q1txvHU2EAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" +
+// "-----END OPENSSH PRIVATE KEY-----";
+//
+// byte[] Bytes3 = null;
+// try {
+// Bytes3 = new PemReader(new StringReader(str3)).readPemObject().getContent();
+// } catch (IOException e1) {
+// e1.printStackTrace();
+// }
+// assert Bytes3 != null;
+// System.out.println(Hex.toHexString(Bytes3));
+//// System.out.println(Hex.toHexString(Base64.decode("oNE9iA4ZyuZLbpEL7B29NaxGi4puT2Y5RDaMoEkoAKI")));
+//// String test = "1ac477fa";
+//// byte[] testBytes = Hex.decode(test);
+////
+//// System.out.println(Base64.toBase64String(testBytes));
+//
+// byte[] AUTH_MAGIC = Strings.toByteArray("openssh-key-v1\0");
+// System.out.println(Hex.toHexString(AUTH_MAGIC));
+// System.out.println(Base64.toBase64String(AUTH_MAGIC));
+// String privKeyStr = "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
+// "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n" +
+// "NhAAAAAwEAAQAAAQEAmMCzeBF8u4NF7oL+JUH6Lo2wEYuPID0sVbqbRrEqBqrEtNHvawO7\n" +
+// "9KsxSmvWYZ8NVpIwpxF0WADIggCWJDP5hiPJm96pHHTYRlmZj56KVfg+OgkxQdeMnkfZo6\n" +
+// "Dj17OKY198xr3iseTcfI73aBXsG0wrXTdMdV1k4zU+W16j/+IF5CxDRFObS7FlQDrtDBPz\n" +
+// "Xv/YDLowLQ6KJSdfNWvT9Om7xKSMOXC7VJ7JuQrbwboi+1gV8QyfyAEiayjRgXSvMYm9fi\n" +
+// "m/LTSwE+g49uQcMpaokTYW+ZdTYuGiqxNhakhHOTcefnLEDBJfTASd6RLCxwTW6IQy/o28\n" +
+// "C4LkVQ+giQAAA9AaxHf6GsR3+gAAAAdzc2gtcnNhAAABAQCYwLN4EXy7g0Xugv4lQfoujb\n" +
+// "ARi48gPSxVuptGsSoGqsS00e9rA7v0qzFKa9Zhnw1WkjCnEXRYAMiCAJYkM/mGI8mb3qkc\n" +
+// "dNhGWZmPnopV+D46CTFB14yeR9mjoOPXs4pjX3zGveKx5Nx8jvdoFewbTCtdN0x1XWTjNT\n" +
+// "5bXqP/4gXkLENEU5tLsWVAOu0ME/Ne/9gMujAtDoolJ181a9P06bvEpIw5cLtUnsm5CtvB\n" +
+// "uiL7WBXxDJ/IASJrKNGBdK8xib1+Kb8tNLAT6Dj25BwylqiRNhb5l1Ni4aKrE2FqSEc5Nx\n" +
+// "5+csQMEl9MBJ3pEsLHBNbohDL+jbwLguRVD6CJAAAAAwEAAQAAAQARfhfPSylei9TpUGTs\n" +
+// "PVb6F82u5K16QqceFiWL/ePTKaEnF9d0CNRwW15kqF6/hShQ3qLlrvEE1uofQRPwh2cuvl\n" +
+// "BrIh95m8PcoowcT0qGN8xgdwcGBDodMhsxSs5suCnD4X53f+1C8/Nv7CtW5xPHuHxKy3dd\n" +
+// "BVn1TvaaHgdn2PwJVKtZp+WVG3/UHr25nFHd8mYgpeHZqK9AW16N0UEMXMM1u8ZCubVOoS\n" +
+// "IGuMAXpTug0xA+BXHo17FcDGKSzcXFzh+urIz5glRp5zFioHBqxNmkKfQkG6C7UxnPGyS/\n" +
+// "/J+3lL2lvl0G8kO/5EDFMBhTMEy1NeR2b629S4G1qUxVAAAAgHDwE9kPiVETcxSzI4wotT\n" +
+// "1Ee9nKVVD3oGdRqefvX7EUR8bvdv4nCqHPNBx8C6l8zo7fsQD81YL85F4eWbtrdxEijRHX\n" +
+// "5m7J/muh/laY1Hq43WCkZGboO4fZ2HHi7oN096FqrKRpvbQGQi1FLbcISUdsitwrs6ywn3\n" +
+// "fNx3q+X3V6AAAAgQDJRo9v+0QvldI33cpJKPKiaop5QvfIDzMatD3vLA1qqycgIi4KOtb5\n" +
+// "+LP/jgIpCYah/sk+JpKNz/vsZmZmrfaVu9D3Le2LLBgMpEoSO8jOe9WGI4Ew75C7w7AZCa\n" +
+// "SyUnHIVX/9D8Y5tx4cKx6Im9AGbNF35XZoKO4KCk5VMTXhnwAAAIEAwkjKIpTYdeAQVTRf\n" +
+// "C13kg84Bu5n4WkiLnp1WOCg2GN5RekqprINtpjIMZoB9Fv292Np99La8yvmRoy5qzNHGdm\n" +
+// "Q6AMku8jP123jF2J+wDvF714VtZHNvdCYBGJS+rZ81xtJfHhKtZqRAVtbPertOWZeuRm9V\n" +
+// "o+/rEuEzgGYGXNcAAAAbemhhbmdsaW4zM0B6aGFuZ2xpbjMzLmxvY2Fs\n" +
+// "-----END OPENSSH PRIVATE KEY-----";
+//
+// byte[] privKeyBytes = null;
+// try {
+// privKeyBytes = new PemReader(new StringReader(privKeyStr)).readPemObject().getContent();
+// } catch (IOException e1) {
+// e1.printStackTrace();
+// }
+//
+// assert privKeyBytes != null;
+// System.out.println(Hex.toHexString(privKeyBytes));
+//
+//
+// OpenSSHPrivateKeySpec privKeySpec = new OpenSSHPrivateKeySpec(privKeyBytes);
+//
+// String privKeyFormat = privKeySpec.getFormat();
+// System.out.println(privKeyFormat);
+//
+// RSAKeyParameters privKey = (RSAKeyParameters) OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privKeyBytes);
+//
+//// BigInteger e = privKey.getPublicExponent();
+//// BigInteger n = privKey.getModulus();
+////
+//// BigInteger d = privKey.getExponent();
+//// BigInteger p = privKey.getP();
+//// BigInteger q = privKey.getQ();
+//// BigInteger dP = privKey.getDP();
+//// BigInteger dQ = privKey.getDQ();
+//// BigInteger qInv = privKey.getQInv();
+//
+//// System.out.println(Hex.toHexString(e.toByteArray()));
+//// System.out.println(Hex.toHexString(n.toByteArray()));
+////
+//// System.out.println(Hex.toHexString(d.toByteArray()));
+//// System.out.println(Hex.toHexString(p.toByteArray()));
+//// System.out.println(Hex.toHexString(q.toByteArray()));
+//// System.out.println(Hex.toHexString(dP.toByteArray()));
+//// System.out.println(Hex.toHexString(dQ.toByteArray()));
+//// System.out.println(Hex.toHexString(qInv.toByteArray()));
+//
+//
+//
+// }
+//
+//}
diff --git a/source/crypto/crypto-pki/pom.xml b/source/crypto/crypto-pki/pom.xml
new file mode 100644
index 00000000..9c895b21
--- /dev/null
+++ b/source/crypto/crypto-pki/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ crypto
+ com.jd.blockchain
+ 0.9.0-SNAPSHOT
+
+ 4.0.0
+
+ crypto-pki
+
+
+
+ com.jd.blockchain
+ crypto-framework
+ ${project.version}
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.61
+
+
+
+ org.bouncycastle
+ bcpkix-jdk15on
+ 1.61
+
+
+
+
+
\ No newline at end of file
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKIAlgorithm.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKIAlgorithm.java
new file mode 100644
index 00000000..0aff4c6b
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKIAlgorithm.java
@@ -0,0 +1,26 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.CryptoAlgorithm;
+import com.jd.blockchain.crypto.CryptoAlgorithmDefinition;
+
+/**
+ * @author zhanglin33
+ * @title: PKIAlgorithm
+ * @description: TODO
+ * @date 2019-05-15, 16:34
+ */
+public class PKIAlgorithm {
+
+ public static final CryptoAlgorithm SHA1WITHRSA2048 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA2048",
+ false, (byte) 31);
+
+ public static final CryptoAlgorithm SHA1WITHRSA4096 = CryptoAlgorithmDefinition.defineSignature("SHA1WITHRSA4096",
+ false, (byte) 32);
+
+ public static final CryptoAlgorithm SM3WITHSM2 = CryptoAlgorithmDefinition.defineSignature("SM3WITHSM2",
+ false, (byte) 33);
+
+ private PKIAlgorithm() {
+ }
+
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKICryptoService.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKICryptoService.java
new file mode 100644
index 00000000..940d3168
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/PKICryptoService.java
@@ -0,0 +1,38 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.CryptoFunction;
+import com.jd.blockchain.crypto.CryptoService;
+import com.jd.blockchain.provider.NamedProvider;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author zhanglin33
+ * @title: PKICryptoService
+ * @description: TODO
+ * @date 2019-05-15, 16:35
+ */
+@NamedProvider("PKI-SOFTWARE")
+public class PKICryptoService implements CryptoService {
+
+ public static final SHA1WITHRSA2048SignatureFunction SHA1WITHRSA2048 = new SHA1WITHRSA2048SignatureFunction();
+
+ public static final SHA1WITHRSA4096SignatureFunction SHA1WITHRSA4096 = new SHA1WITHRSA4096SignatureFunction();
+
+ public static final SM3WITHSM2SignatureFunction SM3WITHSM2 = new SM3WITHSM2SignatureFunction();
+
+ private static final Collection FUNCTIONS;
+
+ static {
+ List funcs = Arrays.asList(SHA1WITHRSA2048, SHA1WITHRSA4096, SM3WITHSM2);
+ FUNCTIONS = Collections.unmodifiableList(funcs);
+ }
+
+ @Override
+ public Collection getFunctions() {
+ return FUNCTIONS;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunction.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunction.java
new file mode 100644
index 00000000..e8eafdad
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunction.java
@@ -0,0 +1,220 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES;
+import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA2048;
+
+/**
+ * @author zhanglin33
+ * @title: SHA1WITHRSA2048SignatureFunction
+ * @description: TODO
+ * @date 2019-05-15, 16:37
+ */
+public class SHA1WITHRSA2048SignatureFunction implements SignatureFunction {
+
+ private static final int RAW_PUBKEY_SIZE = 259;
+ private static final int RAW_PRIVKEY_SIZE = 1155;
+
+ private static final int RAW_SIGNATUREDIGEST_SIZE = 256;
+
+ private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER =
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+ @Override
+ public SignatureDigest sign(PrivKey privKey, byte[] data) {
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA2048 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPrivateCrtKey rawPrivKey;
+ Signature signer;
+ byte[] signature;
+
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
+ signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(rawPrivKey);
+ signer.update(data);
+ signature = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new SignatureDigest(SHA1WITHRSA2048, signature);
+ }
+
+ @Override
+ public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) {
+
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawDigestBytes = digest.getRawDigest();
+
+ if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (pubKey.getAlgorithm() != SHA1WITHRSA2048.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA2048 public key!");
+ }
+
+ if (digest.getAlgorithm() != SHA1WITHRSA2048.code() || rawDigestBytes.length != RAW_SIGNATUREDIGEST_SIZE) {
+ throw new CryptoException("This is not SHA1WITHRSA2048 signature digest!");
+ }
+
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPublicKey rawPubKey;
+ Signature verifier;
+ boolean isValid;
+
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPubKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
+ verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(rawPubKey);
+ verifier.update(data);
+ isValid = verifier.verify(rawDigestBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return isValid;
+ }
+
+ @Override
+ public boolean supportPubKey(byte[] pubKeyBytes) {
+ return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA2048, pubKeyBytes)
+ && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE;
+ }
+
+ @Override
+ public PubKey resolvePubKey(byte[] pubKeyBytes) {
+ if (supportPubKey(pubKeyBytes)) {
+ return new PubKey(pubKeyBytes);
+ } else {
+ throw new CryptoException("pubKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public boolean supportPrivKey(byte[] privKeyBytes) {
+ return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA2048, privKeyBytes)
+ && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE;
+ }
+
+ @Override
+ public PrivKey resolvePrivKey(byte[] privKeyBytes) {
+ if (supportPrivKey(privKeyBytes)) {
+ return new PrivKey(privKeyBytes);
+ } else {
+ throw new CryptoException("privKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public PubKey retrievePubKey(PrivKey privKey) {
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SHA1WITHRSA2048.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA2048 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPrivateCrtKey rawPrivKey;
+ byte[] rawPubKeyBytes;
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
+ BigInteger modulus = rawPrivKey.getModulus();
+ BigInteger exponent = rawPrivKey.getPublicExponent();
+ rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER,
+ new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new PubKey(SHA1WITHRSA2048, rawPubKeyBytes);
+ }
+
+ @Override
+ public boolean supportDigest(byte[] digestBytes) {
+ return digestBytes.length == (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA2048, digestBytes);
+ }
+
+ @Override
+ public SignatureDigest resolveDigest(byte[] digestBytes) {
+ if (supportDigest(digestBytes)) {
+ return new SignatureDigest(digestBytes);
+ } else {
+ throw new CryptoException("digestBytes are invalid!");
+ }
+ }
+
+ @Override
+ public AsymmetricKeypair generateKeypair() {
+
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ KeyPairGenerator generator;
+ PublicKey pubKey;
+ PrivateKey privKey;
+ try {
+ generator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
+ generator.initialize(2048);
+ KeyPair keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ byte[] pubKeyBytes = pubKey.getEncoded();
+ byte[] privKeyBytes = privKey.getEncoded();
+
+ return new AsymmetricKeypair(new PubKey(SHA1WITHRSA2048, pubKeyBytes),
+ new PrivKey(SHA1WITHRSA2048, privKeyBytes));
+ }
+
+ @Override
+ public CryptoAlgorithm getAlgorithm() {
+ return SHA1WITHRSA2048;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunction.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunction.java
new file mode 100644
index 00000000..486096bb
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunction.java
@@ -0,0 +1,220 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES;
+import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SHA1WITHRSA4096;
+
+/**
+ * @author zhanglin33
+ * @title: SHA1WITHRSA4096SignatureFunction
+ * @description: TODO
+ * @date 2019-05-15, 17:13
+ */
+public class SHA1WITHRSA4096SignatureFunction implements SignatureFunction {
+ private static final int RAW_PUBKEY_SIZE = 515;
+ private static final int RAW_PRIVKEY_SIZE = 2307;
+
+ private static final int RAW_SIGNATUREDIGEST_SIZE = 512;
+
+ private static final AlgorithmIdentifier RSA_ALGORITHM_IDENTIFIER =
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+ @Override
+ public SignatureDigest sign(PrivKey privKey, byte[] data) {
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SHA1WITHRSA4096.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA4096 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPrivateCrtKey rawPrivKey;
+ Signature signer;
+ byte[] signature;
+
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
+ signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(rawPrivKey);
+ signer.update(data);
+ signature = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new SignatureDigest(SHA1WITHRSA4096, signature);
+ }
+
+ @Override
+ public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) {
+
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawDigestBytes = digest.getRawDigest();
+
+ if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (pubKey.getAlgorithm() != SHA1WITHRSA4096.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA4096 public key!");
+ }
+
+ if (digest.getAlgorithm() != SHA1WITHRSA4096.code() || rawDigestBytes.length != RAW_SIGNATUREDIGEST_SIZE) {
+ throw new CryptoException("This is not SHA1WITHRSA4096 signature digest!");
+ }
+
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPublicKey rawPubKey;
+ Signature verifier;
+ boolean isValid;
+
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPubKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
+ verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(rawPubKey);
+ verifier.update(data);
+ isValid = verifier.verify(rawDigestBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return isValid;
+ }
+
+ @Override
+ public boolean supportPubKey(byte[] pubKeyBytes) {
+ return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA4096, pubKeyBytes)
+ && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE;
+ }
+
+ @Override
+ public PubKey resolvePubKey(byte[] pubKeyBytes) {
+ if (supportPubKey(pubKeyBytes)) {
+ return new PubKey(pubKeyBytes);
+ } else {
+ throw new CryptoException("pubKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public boolean supportPrivKey(byte[] privKeyBytes) {
+ return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA4096, privKeyBytes)
+ && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE;
+ }
+
+ @Override
+ public PrivKey resolvePrivKey(byte[] privKeyBytes) {
+ if (supportPrivKey(privKeyBytes)) {
+ return new PrivKey(privKeyBytes);
+ } else {
+ throw new CryptoException("privKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public PubKey retrievePubKey(PrivKey privKey) {
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SHA1WITHRSA4096.code()) {
+ throw new CryptoException("This key is not SHA1WITHRSA4096 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ RSAPrivateCrtKey rawPrivKey;
+ byte[] rawPubKeyBytes;
+ try {
+ keyFactory = KeyFactory.getInstance("RSA");
+ rawPrivKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
+ BigInteger modulus = rawPrivKey.getModulus();
+ BigInteger exponent = rawPrivKey.getPublicExponent();
+ rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(RSA_ALGORITHM_IDENTIFIER,
+ new org.bouncycastle.asn1.pkcs.RSAPublicKey(modulus, exponent));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new PubKey(SHA1WITHRSA4096, rawPubKeyBytes);
+ }
+
+ @Override
+ public boolean supportDigest(byte[] digestBytes) {
+ return digestBytes.length == (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE)
+ && CryptoAlgorithm.match(SHA1WITHRSA4096, digestBytes);
+ }
+
+ @Override
+ public SignatureDigest resolveDigest(byte[] digestBytes) {
+ if (supportDigest(digestBytes)) {
+ return new SignatureDigest(digestBytes);
+ } else {
+ throw new CryptoException("digestBytes are invalid!");
+ }
+ }
+
+ @Override
+ public AsymmetricKeypair generateKeypair() {
+
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ KeyPairGenerator generator;
+ PublicKey pubKey;
+ PrivateKey privKey;
+ try {
+ generator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
+ generator.initialize(4096);
+ KeyPair keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ byte[] pubKeyBytes = pubKey.getEncoded();
+ byte[] privKeyBytes = privKey.getEncoded();
+
+ return new AsymmetricKeypair(new PubKey(SHA1WITHRSA4096, pubKeyBytes),
+ new PrivKey(SHA1WITHRSA4096, privKeyBytes));
+ }
+
+
+ @Override
+ public CryptoAlgorithm getAlgorithm() {
+ return SHA1WITHRSA4096;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunction.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunction.java
new file mode 100644
index 00000000..5b9978d7
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunction.java
@@ -0,0 +1,236 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import static com.jd.blockchain.crypto.BaseCryptoKey.KEY_TYPE_BYTES;
+import static com.jd.blockchain.crypto.CryptoBytes.ALGORYTHM_CODE_SIZE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static com.jd.blockchain.crypto.service.pki.PKIAlgorithm.SM3WITHSM2;
+
+/**
+ * @author zhanglin33
+ * @title: SM3WITHSM2SignatureFunction
+ * @description: TODO
+ * @date 2019-05-15, 16:39
+ */
+public class SM3WITHSM2SignatureFunction implements SignatureFunction {
+ private static final int RAW_PUBKEY_SIZE = 65;
+ private static final int RAW_PRIVKEY_SIZE = 32 + 65;
+
+ private static final int RAW_SIGNATUREDIGEST_SIZE = 64;
+
+ private static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
+ private static final BigInteger GX = new BigInteger("32C4AE2C1F1981195F9904466A39C994" +
+ "8FE30BBFF2660BE1715A4589334C74C7", 16);
+ private static final BigInteger GY = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153" +
+ "D0A9877CC62A474002DF32E52139F0A0", 16);
+ private static final ECPoint G = CURVE.createPoint(GX, GY);
+
+ private static final AlgorithmIdentifier SM2_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(
+ X9ObjectIdentifiers.id_ecPublicKey, GMObjectIdentifiers.sm2p256v1);
+
+
+ @Override
+ public SignatureDigest sign(PrivKey privKey, byte[] data) {
+
+ Security.addProvider(new BouncyCastleProvider());
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SM3WITHSM2.code()) {
+ throw new CryptoException("This key is not SM3WITHSM2 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ ECPrivateKey rawPrivKey;
+ Signature signer;
+ byte[] signature;
+
+ try {
+ keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
+ rawPrivKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
+ signer = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME);
+
+ signer.initSign(rawPrivKey);
+ signer.update(data);
+ signature = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException |
+ InvalidKeySpecException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new SignatureDigest(SM3WITHSM2, signature);
+ }
+
+ @Override
+ public boolean verify(SignatureDigest digest, PubKey pubKey, byte[] data) {
+
+ Security.addProvider(new BouncyCastleProvider());
+
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawDigestBytes = digest.getRawDigest();
+
+ if (rawPubKeyBytes.length < RAW_PUBKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (pubKey.getAlgorithm() != SM3WITHSM2.code()) {
+ throw new CryptoException("This key is not SM3WITHSM2 public key!");
+ }
+
+ if (digest.getAlgorithm() != SM3WITHSM2.code() || rawDigestBytes.length < RAW_SIGNATUREDIGEST_SIZE) {
+ throw new CryptoException("This is not SM3WITHSM2 signature digest!");
+ }
+
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(rawPubKeyBytes);
+
+ KeyFactory keyFactory;
+ ECPublicKey rawPubKey;
+ Signature verifier;
+ boolean isValid;
+
+ try {
+ keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
+ rawPubKey = (ECPublicKey) keyFactory.generatePublic(keySpec);
+ verifier = Signature.getInstance("SM3withSM2", BouncyCastleProvider.PROVIDER_NAME);
+ verifier.initVerify(rawPubKey);
+ verifier.update(data);
+ isValid = verifier.verify(rawDigestBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | InvalidKeySpecException
+ | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return isValid;
+ }
+
+ @Override
+ public boolean supportPubKey(byte[] pubKeyBytes) {
+ return pubKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PUBKEY_SIZE)
+ && CryptoAlgorithm.match(SM3WITHSM2, pubKeyBytes)
+ && pubKeyBytes[ALGORYTHM_CODE_SIZE] == PUBLIC.CODE;
+ }
+
+ @Override
+ public PubKey resolvePubKey(byte[] pubKeyBytes) {
+ if (supportPubKey(pubKeyBytes)) {
+ return new PubKey(pubKeyBytes);
+ } else {
+ throw new CryptoException("pubKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public boolean supportPrivKey(byte[] privKeyBytes) {
+ return privKeyBytes.length > (ALGORYTHM_CODE_SIZE + KEY_TYPE_BYTES + RAW_PRIVKEY_SIZE)
+ && CryptoAlgorithm.match(SM3WITHSM2, privKeyBytes)
+ && privKeyBytes[ALGORYTHM_CODE_SIZE] == PRIVATE.CODE;
+ }
+
+ @Override
+ public PrivKey resolvePrivKey(byte[] privKeyBytes) {
+ if (supportPrivKey(privKeyBytes)) {
+ return new PrivKey(privKeyBytes);
+ } else {
+ throw new CryptoException("privKeyBytes are invalid!");
+ }
+ }
+
+ @Override
+ public PubKey retrievePubKey(PrivKey privKey) {
+
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+
+ if (rawPrivKeyBytes.length < RAW_PRIVKEY_SIZE) {
+ throw new CryptoException("This key has wrong format!");
+ }
+
+ if (privKey.getAlgorithm() != SM3WITHSM2.code()) {
+ throw new CryptoException("This key is not SM3WITHSM2 private key!");
+ }
+
+ PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(rawPrivKeyBytes);
+
+ KeyFactory keyFactory;
+ ECPrivateKey rawPrivKey;
+ byte[] rawPubKeyBytes;
+ try {
+ keyFactory = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
+ rawPrivKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
+ BigInteger d = rawPrivKey.getS();
+ ECPoint Q = G.multiply(d).normalize();
+ rawPubKeyBytes = KeyUtil.getEncodedSubjectPublicKeyInfo(SM2_ALGORITHM_IDENTIFIER,
+ Q.getEncoded(false));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return new PubKey(SM3WITHSM2, rawPubKeyBytes);
+ }
+
+ @Override
+ public boolean supportDigest(byte[] digestBytes) {
+ return digestBytes.length > (RAW_SIGNATUREDIGEST_SIZE + ALGORYTHM_CODE_SIZE)
+ && CryptoAlgorithm.match(SM3WITHSM2, digestBytes);
+ }
+
+ @Override
+ public SignatureDigest resolveDigest(byte[] digestBytes) {
+ if (supportDigest(digestBytes)) {
+ return new SignatureDigest(digestBytes);
+ } else {
+ throw new CryptoException("digestBytes are invalid!");
+ }
+ }
+
+ @Override
+ public AsymmetricKeypair generateKeypair() {
+
+ Security.addProvider(new BouncyCastleProvider());
+ KeyPairGenerator generator;
+ PublicKey pubKey;
+ PrivateKey privKey;
+ try {
+ generator = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
+ generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
+ KeyPair keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ byte[] pubKeyBytes = pubKey.getEncoded();
+ byte[] privKeyBytes = privKey.getEncoded();
+
+ return new AsymmetricKeypair(new PubKey(SM3WITHSM2, pubKeyBytes),
+ new PrivKey(SM3WITHSM2, privKeyBytes));
+ }
+ @Override
+ public CryptoAlgorithm getAlgorithm() {
+ return SM3WITHSM2;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CSRBuilder.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CSRBuilder.java
new file mode 100644
index 00000000..790cb7db
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CSRBuilder.java
@@ -0,0 +1,129 @@
+package com.jd.blockchain.crypto.utils;
+
+import com.jd.blockchain.crypto.CryptoException;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.style.BCStrictStyle;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
+import org.bouncycastle.util.encoders.Base64;
+
+import java.io.IOException;
+import java.security.*;
+
+/**
+ * @author zhanglin33
+ * @title: CSRBuilder
+ * @description: A builder for certificate signing request, supporting rsa and sm2
+ * @date 2019-05-10, 15:10
+ */
+public class CSRBuilder {
+
+ private String BC = BouncyCastleProvider.PROVIDER_NAME;
+
+ private PublicKey pubKey;
+ private PrivateKey privKey;
+
+ private String algoName;
+
+ public void init() {
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ algoName = "SHA1withRSA";
+ KeyPairGenerator generator;
+ try {
+ generator = KeyPairGenerator.getInstance("RSA", BC);
+ generator.initialize(2048);
+ KeyPair keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+ }
+
+ public void init(String algoName, int KeyLength) {
+
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ this.algoName = algoName;
+
+ KeyPairGenerator generator;
+ KeyPair keyPair;
+ String[] hashAndSignature = algoName.split("with");
+
+ try {
+ switch (hashAndSignature[1]) {
+ case "RSA": {
+ generator = KeyPairGenerator.getInstance("RSA", BC);
+ generator.initialize(KeyLength);
+ keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ break;
+ }
+
+ case "SM2": {
+ generator = KeyPairGenerator.getInstance("EC", BC);
+ if (KeyLength != 256) {
+ throw new CryptoException("SM3withSM2 with unsupported key length [" +
+ KeyLength +"] in CSR!");
+ }
+ generator.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1"));
+ keyPair = generator.generateKeyPair();
+ pubKey = keyPair.getPublic();
+ privKey = keyPair.getPrivate();
+ break;
+ }
+
+ default: throw new CryptoException("Unsupported algorithm [" + algoName + "] with key length [" +
+ KeyLength +"] in CSR!");
+ }
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+ }
+
+ public String buildRequest(String countryName, String stateName, String cityName,
+ String organizationName, String departmentName, String domainName,
+ String emailName) {
+
+ String result;
+ X500NameBuilder nameBuilder = new X500NameBuilder(BCStrictStyle.INSTANCE);
+
+ nameBuilder.addRDN(BCStyle.C, countryName); // a country name, and China is short as CN
+ nameBuilder.addRDN(BCStyle.ST, stateName); // a state or province name
+ nameBuilder.addRDN(BCStyle.L, cityName); // a city name
+ nameBuilder.addRDN(BCStyle.O, organizationName); // an organization or corporation name
+ nameBuilder.addRDN(BCStyle.OU, departmentName); // a division of your organization name
+ nameBuilder.addRDN(BCStyle.CN, domainName); // a fully qualified domain name
+ nameBuilder.addRDN(BCStyle.E, emailName); // an email address
+
+ try {
+ X500Name x500Name = nameBuilder.build();
+
+ PKCS10CertificationRequestBuilder requestBuilder
+ = new JcaPKCS10CertificationRequestBuilder(x500Name, pubKey);
+ PKCS10CertificationRequest request
+ = requestBuilder.build(new JcaContentSignerBuilder(algoName).setProvider(BC).build(privKey));
+ byte[] csrBytes = request.getEncoded();
+ result = Base64.toBase64String(csrBytes);
+ } catch (OperatorCreationException | IOException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ return result;
+ }
+
+ public PublicKey getPubKey() {
+ return pubKey;
+ }
+
+ public PrivateKey getPrivKey() {
+ return privKey;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CertParser.java b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CertParser.java
new file mode 100644
index 00000000..8267d28b
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/java/com/jd/blockchain/crypto/utils/CertParser.java
@@ -0,0 +1,131 @@
+package com.jd.blockchain.crypto.utils;
+
+import com.jd.blockchain.crypto.CryptoException;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Base64;
+import org.bouncycastle.util.io.pem.PemReader;
+
+import javax.security.auth.x500.X500Principal;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.security.*;
+import java.security.cert.*;
+import java.util.Date;
+
+/**
+ * @author zhanglin33
+ * @title: CertParser
+ * @description: A parser for standard certificate, along with validation process
+ * @date 2019-05-10, 15:17
+ */
+public class CertParser {
+
+ private PublicKey pubKey;
+ private String sigAlgName;
+ private String userName;
+ private String issuerName;
+
+ private Date startTime;
+ private Date endTime;
+
+ public void parse(String userCertificate, String issuerCertificate) {
+
+ X509Certificate issuerCert = parseWithoutValidationProcess(issuerCertificate);
+
+ // ensure that the certificate is within the validity period
+ try {
+ issuerCert.checkValidity();
+ } catch (CertificateExpiredException | CertificateNotYetValidException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+ PublicKey issuerPubKey = issuerCert.getPublicKey();
+ X500Principal issuerPrincipal = issuerCert.getSubjectX500Principal();
+
+ X509Certificate userCert = parseWithoutValidationProcess(userCertificate);
+
+ // check consistency between issuer's names in userCertificate and issuerCertificate
+ if (!userCert.getIssuerX500Principal().equals(issuerPrincipal)) {
+ throw new CryptoException("Issuer in the targeted certificate is not " +
+ "compliance with the parent certificate锛");
+ }
+
+ try {
+ userCert.checkValidity();
+ } catch (CertificateExpiredException | CertificateNotYetValidException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ // verify the signature in certificate with issuer's public key
+ try {
+ userCert.verify(issuerPubKey);
+ } catch (CertificateException | NoSuchAlgorithmException
+ | InvalidKeyException | NoSuchProviderException | SignatureException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+
+ startTime = userCert.getNotBefore();
+ endTime = userCert.getNotAfter();
+
+ pubKey = userCert.getPublicKey();
+ sigAlgName = userCert.getSigAlgName();
+ issuerName = userCert.getIssuerX500Principal().getName();
+ userName = userCert.getSubjectX500Principal().getName();
+ }
+
+ // certificate string in Base64 format
+ public X509Certificate parseWithoutValidationProcess(String certificate) {
+
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+ byte[] certificateBytes;
+ String BEGIN = "-----BEGIN CERTIFICATE-----";
+ String END = "-----END CERTIFICATE-----";
+ if (!certificate.startsWith(BEGIN)) {
+ certificate = certificate.replaceAll("\\n", "");
+ certificate = certificate.replaceAll(END, "");
+ certificateBytes = Base64.decode(certificate);
+ } else {
+ try {
+ certificateBytes = new PemReader(new StringReader(certificate)).readPemObject().getContent();
+ } catch (IOException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+ }
+
+ ByteArrayInputStream bytesIn = new ByteArrayInputStream(certificateBytes);
+ CertificateFactory factory;
+ X509Certificate cert;
+ try {
+ factory = CertificateFactory.getInstance("X509", BouncyCastleProvider.PROVIDER_NAME);
+ cert = (X509Certificate) factory.generateCertificate(bytesIn);
+ } catch (CertificateException | NoSuchProviderException e) {
+ throw new CryptoException(e.getMessage(), e);
+ }
+ return cert;
+ }
+
+ public PublicKey getPubKey() {
+ return pubKey;
+ }
+
+ public String getSigAlgName() {
+ return sigAlgName;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public String getIssuerName() {
+ return issuerName;
+ }
+
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ public Date getEndTime() {
+ return endTime;
+ }
+}
diff --git a/source/crypto/crypto-pki/src/main/resources/META-INF/services/com.jd.blockchain.crypto.CryptoService b/source/crypto/crypto-pki/src/main/resources/META-INF/services/com.jd.blockchain.crypto.CryptoService
new file mode 100644
index 00000000..14a8682f
--- /dev/null
+++ b/source/crypto/crypto-pki/src/main/resources/META-INF/services/com.jd.blockchain.crypto.CryptoService
@@ -0,0 +1 @@
+com.jd.blockchain.crypto.service.pki.PKICryptoService
\ No newline at end of file
diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunctionTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunctionTest.java
new file mode 100644
index 00000000..b7c7d831
--- /dev/null
+++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA2048SignatureFunctionTest.java
@@ -0,0 +1,128 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import com.jd.blockchain.utils.io.BytesUtils;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static com.jd.blockchain.crypto.CryptoAlgorithm.*;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static org.junit.Assert.*;
+
+/**
+ * @author zhanglin33
+ * @title: SHA1WITHRSA2048SignatureFunctionTest
+ * @description: TODO
+ * @date 2019-05-16, 10:49
+ */
+public class SHA1WITHRSA2048SignatureFunctionTest {
+
+ @Test
+ public void getAlgorithmTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA2048");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("SHA1withRsa2048");
+ assertNotNull(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("rsa2048");
+ assertNull(algorithm);
+ }
+
+ @Test
+ public void test() {
+
+ // generateKeyPairTest
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA2048");
+ assertNotNull(algorithm);
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+ PubKey pubKey = keyPair.getPubKey();
+ PrivKey privKey = keyPair.getPrivKey();
+ assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE);
+ assertTrue(pubKey.getRawKeyBytes().length > 259);
+ assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE);
+ assertTrue(privKey.getRawKeyBytes().length > 1155);
+ assertEquals(algorithm.code(), pubKey.getAlgorithm());
+ assertEquals(algorithm.code(), privKey.getAlgorithm());
+ byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
+ byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
+ byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE };
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+ assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes());
+ assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes());
+
+ // retrievePubKeyTest
+ PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey);
+ assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType());
+ assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length);
+ assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm());
+ assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes());
+
+ // signTest
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+ byte[] signatureBytes = signatureDigest.toBytes();
+ assertEquals(2 + 256, signatureBytes.length);
+ assertEquals(algorithm.code(), signatureDigest.getAlgorithm());
+ assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), signatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)),
+ signatureDigest.getAlgorithm());
+
+ byte[] rawSinatureBytes = signatureDigest.getRawDigest();
+ assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes);
+
+ // verifyTest
+ assertTrue(signatureFunction.verify(signatureDigest, pubKey, data));
+
+ // supportPrivKeyTest
+ byte[] privKeyBytes = privKey.toBytes();
+ assertTrue(signatureFunction.supportPrivKey(privKeyBytes));
+
+ // resolvePrivKeyTest
+ PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes);
+ assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedPrivKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)),
+ resolvedPrivKey.getAlgorithm());
+ assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes());
+
+ // supportPubKeyTest
+ byte[] pubKeyBytes = pubKey.toBytes();
+ assertTrue(signatureFunction.supportPubKey(pubKeyBytes));
+
+ // resolvedPubKeyTest
+ PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes);
+ assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedPubKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)),
+ resolvedPubKey.getAlgorithm());
+ assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes());
+
+ //supportDigestTest
+ byte[] signatureDigestBytes = signatureDigest.toBytes();
+ assertTrue(signatureFunction.supportDigest(signatureDigestBytes));
+
+ // resolveDigestTest
+ SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes);
+ assertEquals(256, resolvedSignatureDigest.getRawDigest().length);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA2048.code(), resolvedSignatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 31 & 0x00FF)),
+ resolvedSignatureDigest.getAlgorithm());
+ assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
+ }
+}
diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunctionTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunctionTest.java
new file mode 100644
index 00000000..9444771b
--- /dev/null
+++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SHA1WITHRSA4096SignatureFunctionTest.java
@@ -0,0 +1,128 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import com.jd.blockchain.utils.io.BytesUtils;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY;
+import static com.jd.blockchain.crypto.CryptoAlgorithm.SIGNATURE_ALGORITHM;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static org.junit.Assert.*;
+
+/**
+ * @author zhanglin33
+ * @title: SHA1WITHRSA4096SignatureFunctionTest
+ * @description: TODO
+ * @date 2019-05-16, 10:49
+ */
+public class SHA1WITHRSA4096SignatureFunctionTest {
+
+ @Test
+ public void getAlgorithmTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA4096");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("SHA1withRsa4096");
+ assertNotNull(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("rsa2048");
+ assertNull(algorithm);
+ }
+
+ //@Test
+ public void generateKeyPairTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SHA1WITHRSA4096");
+ assertNotNull(algorithm);
+
+ AsymmetricKeypair keyPair = Crypto.getSignatureFunction(algorithm).generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ PrivKey privKey = keyPair.getPrivKey();
+
+ assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE);
+ assertTrue(pubKey.getRawKeyBytes().length > 515);
+ assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE);
+ assertTrue(privKey.getRawKeyBytes().length > 2307);
+
+ assertEquals(algorithm.code(), pubKey.getAlgorithm());
+ assertEquals(algorithm.code(), privKey.getAlgorithm());
+
+ byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
+ byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
+ byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE };
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+ assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes());
+ assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes());
+
+ // retrievePubKeyTest
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+ PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey);
+ assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType());
+ assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length);
+ assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm());
+ assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes());
+
+
+ // signAndVerifyTest
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+ byte[] signatureBytes = signatureDigest.toBytes();
+ assertEquals(2 + 512, signatureBytes.length);
+ assertEquals(algorithm.code(), signatureDigest.getAlgorithm());
+ assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), signatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)),
+ signatureDigest.getAlgorithm());
+ algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm());
+ byte[] rawSinatureBytes = signatureDigest.getRawDigest();
+ assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes);
+ assertTrue(signatureFunction.verify(signatureDigest, pubKey, data));
+
+ // supportAndResolvePrivKeyTest
+ byte[] privKeyBytes = privKey.toBytes();
+ assertTrue(signatureFunction.supportPrivKey(privKeyBytes));
+ PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes);
+ assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedPrivKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)),
+ resolvedPrivKey.getAlgorithm());
+ assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes());
+
+ // supportAndResolvePubKeyTest
+ byte[] pubKeyBytes = pubKey.toBytes();
+ assertTrue(signatureFunction.supportPubKey(pubKeyBytes));
+ PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes);
+ assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedPubKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)),
+ resolvedPubKey.getAlgorithm());
+ assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes());
+
+
+ // supportAndResolveDigestTest
+ byte[] signatureDigestBytes = signatureDigest.toBytes();
+ assertTrue(signatureFunction.supportDigest(signatureDigestBytes));
+ SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes);
+ assertEquals(512, resolvedSignatureDigest.getRawDigest().length);
+ assertEquals(PKIAlgorithm.SHA1WITHRSA4096.code(), resolvedSignatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 32 & 0x00FF)),
+ resolvedSignatureDigest.getAlgorithm());
+ assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
+ }
+}
diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunctionTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunctionTest.java
new file mode 100644
index 00000000..0b8063a9
--- /dev/null
+++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/service/pki/SM3WITHSM2SignatureFunctionTest.java
@@ -0,0 +1,273 @@
+package com.jd.blockchain.crypto.service.pki;
+
+import com.jd.blockchain.crypto.*;
+import com.jd.blockchain.utils.io.BytesUtils;
+import org.junit.Test;
+
+import java.util.Random;
+
+import static com.jd.blockchain.crypto.CryptoAlgorithm.ASYMMETRIC_KEY;
+import static com.jd.blockchain.crypto.CryptoAlgorithm.SIGNATURE_ALGORITHM;
+import static com.jd.blockchain.crypto.CryptoKeyType.PRIVATE;
+import static com.jd.blockchain.crypto.CryptoKeyType.PUBLIC;
+import static org.junit.Assert.*;
+
+/**
+ * @author zhanglin33
+ * @title: SM3WITHSM2SignatureFunctionTest
+ * @description: TODO
+ * @date 2019-05-16, 17:04
+ */
+public class SM3WITHSM2SignatureFunctionTest {
+
+ @Test
+ public void getAlgorithmTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("sm3withsm2");
+ assertNotNull(algorithm);
+
+ assertEquals(signatureFunction.getAlgorithm().name(), algorithm.name());
+ assertEquals(signatureFunction.getAlgorithm().code(), algorithm.code());
+
+ algorithm = Crypto.getAlgorithm("sm3withs");
+ assertNull(algorithm);
+ }
+
+ @Test
+ public void generateKeyPairTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ PrivKey privKey = keyPair.getPrivKey();
+
+ assertEquals(PUBLIC.CODE, pubKey.getKeyType().CODE);
+ assertTrue(pubKey.getRawKeyBytes().length > 32);
+ assertEquals(PRIVATE.CODE, privKey.getKeyType().CODE);
+ assertTrue(privKey.getRawKeyBytes().length > 65 + 32);
+
+ assertEquals(algorithm.code(), pubKey.getAlgorithm());
+ assertEquals(algorithm.code(), privKey.getAlgorithm());
+
+ byte[] algoBytes = CryptoAlgorithm.getCodeBytes(algorithm);
+ byte[] pubKeyTypeBytes = new byte[] { PUBLIC.CODE };
+ byte[] privKeyTypeBytes = new byte[] { PRIVATE.CODE };
+ byte[] rawPubKeyBytes = pubKey.getRawKeyBytes();
+ byte[] rawPrivKeyBytes = privKey.getRawKeyBytes();
+ assertArrayEquals(BytesUtils.concat(algoBytes, pubKeyTypeBytes, rawPubKeyBytes), pubKey.toBytes());
+ assertArrayEquals(BytesUtils.concat(algoBytes, privKeyTypeBytes, rawPrivKeyBytes), privKey.toBytes());
+ }
+
+ @Test
+ public void retrievePubKeyTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ PrivKey privKey = keyPair.getPrivKey();
+
+ PubKey retrievedPubKey = signatureFunction.retrievePubKey(privKey);
+
+ assertEquals(pubKey.getKeyType(), retrievedPubKey.getKeyType());
+ assertEquals(pubKey.getRawKeyBytes().length, retrievedPubKey.getRawKeyBytes().length);
+ assertEquals(pubKey.getAlgorithm(), retrievedPubKey.getAlgorithm());
+ assertArrayEquals(pubKey.toBytes(), retrievedPubKey.toBytes());
+ }
+
+ @Test
+ public void signTest() {
+
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PrivKey privKey = keyPair.getPrivKey();
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+
+ byte[] signatureBytes = signatureDigest.toBytes();
+
+ assertTrue(signatureBytes.length > 2 + 64);
+ assertEquals(algorithm.code(), signatureDigest.getAlgorithm());
+
+ assertEquals(PKIAlgorithm.SM3WITHSM2.code(), signatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)),
+ signatureDigest.getAlgorithm());
+
+ byte[] algoBytes = BytesUtils.toBytes(signatureDigest.getAlgorithm());
+ byte[] rawSinatureBytes = signatureDigest.getRawDigest();
+ assertArrayEquals(BytesUtils.concat(algoBytes, rawSinatureBytes), signatureBytes);
+ }
+
+ @Test
+ public void verifyTest() {
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ PrivKey privKey = keyPair.getPrivKey();
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+
+ System.out.println(signatureDigest.getRawDigest().length);
+ assertTrue(signatureFunction.verify(signatureDigest, pubKey, data));
+ }
+
+ @Test
+ public void supportPrivKeyTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PrivKey privKey = keyPair.getPrivKey();
+ byte[] privKeyBytes = privKey.toBytes();
+
+ assertTrue(signatureFunction.supportPrivKey(privKeyBytes));
+ }
+
+ @Test
+ public void resolvePrivKeyTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PrivKey privKey = keyPair.getPrivKey();
+ byte[] privKeyBytes = privKey.toBytes();
+
+ PrivKey resolvedPrivKey = signatureFunction.resolvePrivKey(privKeyBytes);
+
+ assertEquals(PRIVATE.CODE, resolvedPrivKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SM3WITHSM2.code(), resolvedPrivKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)),
+ resolvedPrivKey.getAlgorithm());
+ assertArrayEquals(privKeyBytes, resolvedPrivKey.toBytes());
+ }
+
+ @Test
+ public void supportPubKeyTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ byte[] pubKeyBytes = pubKey.toBytes();
+
+ assertTrue(signatureFunction.supportPubKey(pubKeyBytes));
+ }
+
+ @Test
+ public void resolvePubKeyTest() {
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PubKey pubKey = keyPair.getPubKey();
+ byte[] pubKeyBytes = pubKey.toBytes();
+
+ PubKey resolvedPubKey = signatureFunction.resolvePubKey(pubKeyBytes);
+
+ assertEquals(PUBLIC.CODE, resolvedPubKey.getKeyType().CODE);
+ assertEquals(PKIAlgorithm.SM3WITHSM2.code(), resolvedPubKey.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)),
+ resolvedPubKey.getAlgorithm());
+ assertArrayEquals(pubKeyBytes, resolvedPubKey.toBytes());
+ }
+
+ @Test
+ public void supportDigestTest() {
+
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PrivKey privKey = keyPair.getPrivKey();
+
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+
+ byte[] signatureDigestBytes = signatureDigest.toBytes();
+ assertTrue(signatureFunction.supportDigest(signatureDigestBytes));
+ }
+
+ @Test
+ public void resolveDigestTest() {
+
+ byte[] data = new byte[1024];
+ Random random = new Random();
+ random.nextBytes(data);
+
+ CryptoAlgorithm algorithm = Crypto.getAlgorithm("SM3WITHSM2");
+ assertNotNull(algorithm);
+
+ SignatureFunction signatureFunction = Crypto.getSignatureFunction(algorithm);
+
+ AsymmetricKeypair keyPair = signatureFunction.generateKeypair();
+
+ PrivKey privKey = keyPair.getPrivKey();
+
+ SignatureDigest signatureDigest = signatureFunction.sign(privKey, data);
+
+ byte[] signatureDigestBytes = signatureDigest.toBytes();
+
+ SignatureDigest resolvedSignatureDigest = signatureFunction.resolveDigest(signatureDigestBytes);
+
+ assertTrue(resolvedSignatureDigest.getRawDigest().length > 64);
+ assertEquals(PKIAlgorithm.SM3WITHSM2.code(), resolvedSignatureDigest.getAlgorithm());
+ assertEquals((short) (SIGNATURE_ALGORITHM | ASYMMETRIC_KEY | ((byte) 33 & 0x00FF)),
+ resolvedSignatureDigest.getAlgorithm());
+ assertArrayEquals(signatureDigestBytes, resolvedSignatureDigest.toBytes());
+ }
+}
diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CSRBuilderTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CSRBuilderTest.java
new file mode 100644
index 00000000..62dc4dc2
--- /dev/null
+++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CSRBuilderTest.java
@@ -0,0 +1,396 @@
+package com.jd.blockchain.crypto.utils;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.util.encoders.Base64;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.security.*;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author zhanglin33
+ * @title: CSRBuilderTest
+ * @description: TODO
+ * @date 2019-05-10, 17:22
+ */
+public class CSRBuilderTest {
+
+ @Test
+ public void defaultCSRTest(){
+
+ String countryName = "CN";
+ String stateName = "Beijing";
+ String cityName = "Beijing";
+ String organizationName = "JD.com";
+ String departmentName = "Blockchain Department";
+ String domainName = "ledger.jd.com";
+ String emailName = "zhanglin33@jd.com";
+
+ CSRBuilder builder = new CSRBuilder();
+
+ builder.init();
+ String csr = builder.buildRequest(countryName,stateName,cityName,
+ organizationName,departmentName,domainName,
+ emailName);
+
+ PublicKey pubKey = builder.getPubKey();
+ PrivateKey privKey = builder.getPrivKey();
+
+ byte[] crsBytes = Base64.decode(csr);
+ PKCS10CertificationRequest request = null;
+ try {
+ request = new PKCS10CertificationRequest(crsBytes);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertNotNull(request);
+ assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId());
+ byte[] pubKeyBytes = new byte[0];
+ try {
+ pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(pubKeyBytes,pubKey.getEncoded());
+
+ RDN[] rdns = request.getSubject().getRDNs();
+ assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive());
+
+ assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString());
+
+ byte[] signature = request.getSignature();
+
+ CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet());
+ byte[] message = new byte[0];
+ try {
+ message = requestInfo.getEncoded(ASN1Encoding.DER);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ Signature signer;
+ byte[] result = new byte[0];
+ try {
+ signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(privKey);
+ signer.update(message);
+ result = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(result,signature);
+
+ Signature verifier;
+ boolean isValid = false;
+ try {
+ verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(pubKey);
+ verifier.update(message);
+ isValid = verifier.verify(signature);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isValid);
+ }
+
+ @Test
+ public void SHA1withRSA2048CSRTest(){
+
+ String countryName = "CN";
+ String stateName = "Beijing";
+ String cityName = "Beijing";
+ String organizationName = "JD.com";
+ String departmentName = "Blockchain Department";
+ String domainName = "ledger.jd.com";
+ String emailName = "zhanglin33@jd.com";
+
+ CSRBuilder builder = new CSRBuilder();
+
+ builder.init("SHA1withRSA",2048);
+ String csr = builder.buildRequest(countryName,stateName,cityName,
+ organizationName,departmentName,domainName,
+ emailName);
+
+ PublicKey pubKey = builder.getPubKey();
+ PrivateKey privKey = builder.getPrivKey();
+
+ byte[] crsBytes = Base64.decode(csr);
+ PKCS10CertificationRequest request = null;
+ try {
+ request = new PKCS10CertificationRequest(crsBytes);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertNotNull(request);
+ assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId());
+ byte[] pubKeyBytes = new byte[0];
+ try {
+ pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(pubKeyBytes,pubKey.getEncoded());
+
+ RDN[] rdns = request.getSubject().getRDNs();
+ assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive());
+
+ assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString());
+
+ byte[] signature = request.getSignature();
+
+ CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet());
+ byte[] message = new byte[0];
+ try {
+ message = requestInfo.getEncoded(ASN1Encoding.DER);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ Signature signer;
+ byte[] result = new byte[0];
+ try {
+ signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(privKey);
+ signer.update(message);
+ result = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(result,signature);
+
+ Signature verifier;
+ boolean isValid = false;
+ try {
+ verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(pubKey);
+ verifier.update(message);
+ isValid = verifier.verify(signature);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isValid);
+ }
+
+
+// @Test
+ public void SHA1withRSA4096CSRTest(){
+
+ String countryName = "CN";
+ String stateName = "Beijing";
+ String cityName = "Beijing";
+ String organizationName = "JD.com";
+ String departmentName = "Blockchain Department";
+ String domainName = "ledger.jd.com";
+ String emailName = "zhanglin33@jd.com";
+
+ CSRBuilder builder = new CSRBuilder();
+
+ builder.init("SHA1withRSA",4096);
+ String csr = builder.buildRequest(countryName,stateName,cityName,
+ organizationName,departmentName,domainName,
+ emailName);
+
+ PublicKey pubKey = builder.getPubKey();
+ PrivateKey privKey = builder.getPrivKey();
+
+ byte[] crsBytes = Base64.decode(csr);
+ PKCS10CertificationRequest request = null;
+ try {
+ request = new PKCS10CertificationRequest(crsBytes);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertNotNull(request);
+ assertEquals("1.2.840.113549.1.1.5",request.getSignatureAlgorithm().getAlgorithm().getId());
+ byte[] pubKeyBytes = new byte[0];
+ try {
+ pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(pubKeyBytes,pubKey.getEncoded());
+
+ RDN[] rdns = request.getSubject().getRDNs();
+ assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive());
+
+ assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString());
+
+ byte[] signature = request.getSignature();
+
+ CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet());
+ byte[] message = new byte[0];
+ try {
+ message = requestInfo.getEncoded(ASN1Encoding.DER);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ Signature signer;
+ byte[] result = new byte[0];
+ try {
+ signer = Signature.getInstance("SHA1withRSA");
+ signer.initSign(privKey);
+ signer.update(message);
+ result = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(result,signature);
+
+ Signature verifier;
+ boolean isValid = false;
+ try {
+ verifier = Signature.getInstance("SHA1withRSA");
+ verifier.initVerify(pubKey);
+ verifier.update(message);
+ isValid = verifier.verify(signature);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isValid);
+ }
+
+
+ @Test
+ public void SM3withSM2CSRTest(){
+
+ String countryName = "CN";
+ String stateName = "Beijing";
+ String cityName = "Beijing";
+ String organizationName = "JD.com";
+ String departmentName = "Blockchain Department";
+ String domainName = "ledger.jd.com";
+ String emailName = "zhanglin33@jd.com";
+
+ CSRBuilder builder = new CSRBuilder();
+
+ builder.init("SM3withSM2",256);
+ String csr = builder.buildRequest(countryName,stateName,cityName,
+ organizationName,departmentName,domainName,
+ emailName);
+
+ System.out.println(csr);
+ PublicKey pubKey = builder.getPubKey();
+ PrivateKey privKey = builder.getPrivKey();
+
+ byte[] crsBytes = Base64.decode(csr);
+ PKCS10CertificationRequest request = null;
+ try {
+ request = new PKCS10CertificationRequest(crsBytes);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertNotNull(request);
+ assertEquals("1.2.156.10197.1.501",request.getSignatureAlgorithm().getAlgorithm().getId());
+ byte[] pubKeyBytes = new byte[0];
+ try {
+ pubKeyBytes = request.getSubjectPublicKeyInfo().getEncoded();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ assertArrayEquals(pubKeyBytes,pubKey.getEncoded());
+
+ RDN[] rdns = request.getSubject().getRDNs();
+ assertEquals(BCStyle.C, rdns[0].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.ST, rdns[1].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.L, rdns[2].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.O, rdns[3].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.OU, rdns[4].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.CN, rdns[5].getFirst().getType().toASN1Primitive());
+ assertEquals(BCStyle.E, rdns[6].getFirst().getType().toASN1Primitive());
+
+ assertEquals("CN", rdns[0].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[1].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Beijing", rdns[2].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("JD.com", rdns[3].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("Blockchain Department", rdns[4].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("ledger.jd.com", rdns[5].getFirst().getValue().toASN1Primitive().toString());
+ assertEquals("zhanglin33@jd.com", rdns[6].getFirst().getValue().toASN1Primitive().toString());
+
+ byte[] signature = request.getSignature();
+
+ CertificationRequestInfo requestInfo = new CertificationRequestInfo(request.getSubject(),request.getSubjectPublicKeyInfo(),new DERSet());
+ byte[] message = new byte[0];
+ try {
+ message = requestInfo.getEncoded(ASN1Encoding.DER);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ Signature signer;
+ byte[] result = new byte[0];
+ try {
+ signer = Signature.getInstance("SM3withSM2");
+ signer.initSign(privKey);
+ signer.update(message);
+ result = signer.sign();
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+
+ Signature verifier;
+ boolean isValid = false;
+ try {
+ verifier = Signature.getInstance("SM3withSM2");
+ verifier.initVerify(pubKey);
+ verifier.update(message);
+ isValid = verifier.verify(signature);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isValid);
+
+ try {
+ verifier = Signature.getInstance("SM3withSM2");
+ verifier.initVerify(pubKey);
+ verifier.update(message);
+ isValid = verifier.verify(result);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ e.printStackTrace();
+ }
+ assertTrue(isValid);
+ }
+}
diff --git a/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CertParserTest.java b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CertParserTest.java
new file mode 100644
index 00000000..24cdc414
--- /dev/null
+++ b/source/crypto/crypto-pki/src/test/java/com/jd/blockchain/crypto/utils/CertParserTest.java
@@ -0,0 +1,146 @@
+package com.jd.blockchain.crypto.utils;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @author zhanglin33
+ * @title: CertParserTest
+ * @description: TODO
+ * @date 2019-05-13, 10:05
+ */
+public class CertParserTest {
+
+ @Test
+ public void parseSHA1WITHRSA2048Test() {
+ CertParser parser = new CertParser();
+ String issuerCert =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" +
+ "VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" +
+ "QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" +
+ "NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" +
+ "bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" +
+ "RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" +
+ "jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" +
+ "jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" +
+ "bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" +
+ "RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" +
+ "0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" +
+ "t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" +
+ "aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" +
+ "Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" +
+ "MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" +
+ "AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" +
+ "3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" +
+ "/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" +
+ "/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" +
+ "fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" +
+ "OMRZvB7FRyE9IfwKApngcZbA5g==\n" +
+ "-----END CERTIFICATE-----";
+
+ String userCert = "MIIEQDCCAyigAwIBAgIFICdVYzEwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxMDExMjAyNFoXDTIxMDUxMDExMjAyNFowcjELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTEfMB0GA1UEAxQWMDUxQGFhYWFhQFpIMDkzNTgwMjhAMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJx3F2WD1dJPzK/nRHO7d1TJ1hTjzGTmv0PQ7ECsJAh3U3BtnGTpCB+b4+JMI4LO8nHkKIBQ3P9XnF+Bf1iXdWNAQ4aWCxa2nV7lCp4w0GliPu/EMgIfmsSDUtgqbM3cr8sR8r9m1xG3gt2TIQJ+jT7sAiguU/kyNzpjaccOUIgUFa8IDFq9UeB76MXtCuhlERRZQCl47e+9w7ZoxmE7e6IZORxPp7rQWVBHlR9ntWjJfNDTm3gMP5ehP+yIZnKx1LudxkBLQxpMmspzOyH1zqx5nkKe49AfWWpDxxRvYkriyYC3aE81qLsU/bhLwNEKOju7BGDF/mhJLZUedojM0gMCAwEAAaOB9TCB8jAfBgNVHSMEGDAWgBT8C7xEmg4xoYOpgYcnHgVCxr9W+DBIBgNVHSAEQTA/MD0GCGCBHIbvKgECMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2ZjYS5jb20uY24vdXMvdXMtMTUuaHRtMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly8yMTAuNzQuNDIuMy9PQ0ExMS9SU0EvY3JsMjU2OTMuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU5oKGaQs7Jt5Gfbt1XhFTWAySEKswHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAlmPRaImZV51iKjtpMKuyLMw7dX8L0lY3tl+pVZZSxHuwsN4GCCtV0Ej50up+/6EbfL4NUTiuHVAjCroKKvb+94CrdEwdnQGM5IbGSjT78nQpeASXbIWuUwA+ImjvZOzvq/0b56AzonNzBxOMGko/bj5smM6X8jrgJ0NQppo2KNSVNC4JbuoNWI4FM94SE4DUi9H7EYl4JdOtDaDtCsq49o/A1CZyYrmoOPCgxpQQXmuB3lGq/jyoOlW2aW8uee/hYG1JJcSHLBjF0WBwdxssgbBotA5f1PebiIMSbFgjk57bd4M80hhU/rI4Hkn9pcp5R7NsX95TtyDIg90LboBnW";
+
+ parser.parse(userCert, issuerCert);
+ assertEquals("SHA1WITHRSA",parser.getSigAlgName());
+ }
+
+ @Test
+ public void parseSHA1WITHRSA4096Test() {
+ CertParser parser = new CertParser();
+ String issuerCert =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDzzCCAregAwIBAgIKUalCR1Mt5ZSK8jANBgkqhkiG9w0BAQUFADBZMQswCQYD\n" +
+ "VQQGEwJDTjEwMC4GA1UEChMnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24g\n" +
+ "QXV0aG9yaXR5MRgwFgYDVQQDEw9DRkNBIFRFU1QgQ1MgQ0EwHhcNMTIwODI5MDU1\n" +
+ "NDM2WhcNMzIwODI0MDU1NDM2WjBZMQswCQYDVQQGEwJDTjEwMC4GA1UEChMnQ2hp\n" +
+ "bmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRgwFgYDVQQDEw9D\n" +
+ "RkNBIFRFU1QgT0NBMTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8\n" +
+ "jn0n8Fp6hcRdACdn1+Y6GAkC6KGgNdKyHPrmsdmhCjnd/i4qUFwnG8cp3D4lFw1G\n" +
+ "jmjSO5yVYbik/NbS6lbNpRgTK3fDfMFvLJpRIC+IFhG9SdAC2hwjsH9qTpL9cK2M\n" +
+ "bSdrC6pBdDgnbzaM9AGBF4Y6vXhj5nah4ZMsBvDp19LzXjlGuTPLuAgv9ZlWknsd\n" +
+ "RN70PIAmvomd10uqX4GIJ4Jq/FdKXOLZ2DNK/NhRyN6Yq71L3ham6tutXeZow5t5\n" +
+ "0254AnUlo1u6SeH9F8itER653o/oMLFwp+63qXAcqrHUlOQPX+JI8fkumSqZ4F2F\n" +
+ "t/HfVMnqdtFNCnh5+eIBAgMBAAGjgZgwgZUwHwYDVR0jBBgwFoAUdN7FjQp9EBqq\n" +
+ "aYNbTSHOhpvMcTgwDAYDVR0TBAUwAwEB/zA4BgNVHR8EMTAvMC2gK6AphidodHRw\n" +
+ "Oi8vMjEwLjc0LjQyLjMvdGVzdHJjYS9SU0EvY3JsMS5jcmwwCwYDVR0PBAQDAgEG\n" +
+ "MB0GA1UdDgQWBBT8C7xEmg4xoYOpgYcnHgVCxr9W+DANBgkqhkiG9w0BAQUFAAOC\n" +
+ "AQEAb7W0K9fZPA+JPw6lRiMDaUJ0oh052yEXreMBfoPulxkBj439qombDiFggRLc\n" +
+ "3g8wIEKzMOzOKXTWtnzYwN3y/JQSuJb/M1QqOEEM2PZwCxI4AkBuH6jg03RjlkHg\n" +
+ "/kTtuIFp9ItBCC2/KkKlp0ENfn4XgVg2KtAjZ7lpyVU0LPnhEqqUVY/xthjlCSa7\n" +
+ "/XHNStRxsfCTIBUWJ8n2FZyQhfV/UkMNHDBIiJR0v6C4Ai0/290WvbPEIAq+03Si\n" +
+ "fsHzBeA0C8lP5VzfAr6wWePaZMCpStpLaoXNcAqReKxQllElOqAhRxC5VKH+rnIQ\n" +
+ "OMRZvB7FRyE9IfwKApngcZbA5g==\n" +
+ "-----END CERTIFICATE-----";
+
+ String userCert = "MIIFRjCCBC6gAwIBAgIFICdWiDMwDQYJKoZIhvcNAQEFBQAwWTELMAkGA1UEBhMCQ04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEYMBYGA1UEAxMPQ0ZDQSBURVNUIE9DQTExMB4XDTE5MDUxNjA3MDcyMloXDTIxMDUxNjA3MDcyMloweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoTD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECxMITG9jYWwgUkExFTATBgNVBAsTDEluZGl2aWR1YWwtMTElMCMGA1UEAxQcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL0rTOxd8rsjPtFJ0aGVh9bZPy5Xo0SADaP7BbJsG4+ykLQMZHg9hTf/6fv1OsD2HEKFoMpIkW2gwCJW2nvicHcVql/shCoktc6ZBW6Dr/DxOgbO9tpoGxZ50xdI4Q0NsrxqtbCldW4ozPHdjgRJ83i1KSFh7evNrVByN/mB+jchrVGLWyJ1uIRgUUgpRZmZPoOHaizVJqrqWJGGk6xbDLR2gUQ1hTzetQaz1OeKtelHDk9FY08XSmNGssSMpuSjrxn78S888VW5WIxyo4cwrXSXFk3J7LNTy70Oga16HZjJD/vLTM6a4riPa8+uivPinKxK38/++nlBPNwhx6n46uYkd9Zvw+SJiJgpnuPJLtMZpKpJx7V1BDVEydKPUthilTdsmJtkBFSlFw0G1aKfuciBGzzJ3SKngJF/JqJAWIonVAFBGb6Gokp1Sw+T4KqXrdbjxYxiyyjZ++8O1vydgFAkx/NjsuwJnpKETiRKFJmY7YawcUvC4ixF7XQc0luFWRDYcbxOppir+ieMqhGXyaFhLUuB4WXv+rFxfa3NmkBW8q5TPzt/PwWcXpITsYTZYla/E/grB+OeZLYgjigT5YlgytPHG6Gt1ySCCd8WXFWpkBbQfXzqcvtU27RCcAUgfXk5NLb7NZCQg7heGjgzOdYJCPsa1d3m7l04+VIKGCZdAgMBAAGjgfUwgfIwHwYDVR0jBBgwFoAU/Au8RJoOMaGDqYGHJx4FQsa/VvgwSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA6BgNVHR8EMzAxMC+gLaArhilodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvUlNBL2NybDI1NzE3LmNybDALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFMjh6AzDCuNkD+pqQfiS6bqPGpI4MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDANBgkqhkiG9w0BAQUFAAOCAQEApZaLXS6/6FudPA3l2xom5U7nJUOpQ1E6DO/ic9dFGtLE0WgyAqB3JVPvXEntppX55x/dAV7rvvz9NaEdiAe8DAj7qyoPDvC8ZWQK8U4n9l8N78QwALOURxzQNs+CBatJQzbu2w1RKVwkfE6xEIVnu+wjiAtymfwdLHMagHxDIC/eOPbTnbbtITJk2ukFfoc0WJ6Awg5lW+x7nGokEn/XAjKyRHCpkRUFGQm4ww41zlrqCqQqnVGVABJtjbdtFf7nh33QHl0fkj19nfMox9eGuntPyM0bNA0XqPMA+FWSCqeDT6uLbyaOKWxlhv53U/NCJl76U3tssMEWsm9amEDDQg==";
+
+ parser.parse(userCert, issuerCert);
+ assertEquals("SHA1WITHRSA",parser.getSigAlgName());
+ }
+
+ @Test
+ public void parseSM3WITHSM2Test() {
+ CertParser parser = new CertParser();
+ String issuerCert =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" +
+ "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" +
+ "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" +
+ "MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" +
+ "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" +
+ "DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" +
+ "L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" +
+ "9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" +
+ "w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" +
+ "MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" +
+ "VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" +
+ "AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" +
+ "PrIDl+E4aL3FypntFXHG3T+Keg==\n" +
+ "-----END CERTIFICATE-----";
+
+ String userCert = "MIICwDCCAmWgAwIBAgIFICdWkWgwDAYIKoEcz1UBg3UFADBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQDDBNDRkNBIFRFU1QgU00yIE9DQTExMB4XDTE5MDUxNjA4MTA1MVoXDTIxMDUxNjA4MTA1MVoweDELMAkGA1UEBhMCQ04xGDAWBgNVBAoMD0NGQ0EgVEVTVCBPQ0ExMTERMA8GA1UECwwITG9jYWwgUkExFTATBgNVBAsMDEluZGl2aWR1YWwtMTElMCMGA1UEAwwcMDUxQHpoYW5nbGluIUBaMTg2MTIyMjkyOTVAMzBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABPvNXpdZ4/4g+wx5qKS94CPkMqpEDhlnXYYW7ZzsbNI4d28sVBz5Ji6dTT1Zx627Kvw4tdUaUt7BVMvZsu3BFlyjgfQwgfEwHwYDVR0jBBgwFoAUvqZ+TT18j6BV5sEvCS4sIEOzQn8wSAYDVR0gBEEwPzA9BghggRyG7yoBAjAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3VzL3VzLTE1Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vMjEwLjc0LjQyLjMvT0NBMTEvU00yL2NybDIxMDkuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUxR5C/VjASus5zrAAFS4ulMpRjKgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMAwGCCqBHM9VAYN1BQADRwAwRAIgVBzVi/fgkknr+2BH2wXeGMXC+Pa6p7rbldUsYMOYoyUCIAmQ4KEk2U1xJZSBpOPy5jN9kmRb+0YH6x04O/2tqCgq";
+
+ parser.parse(userCert, issuerCert);
+ assertEquals("SM3WITHSM2",parser.getSigAlgName());
+ }
+
+ @Test
+ public void authenticateIssuerByCATest() {
+ CertParser parser = new CertParser();
+ String CACert =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIICFDCCAbegAwIBAgIKPYozwkCO86Nd9TAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" +
+ "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" +
+ "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" +
+ "MDMyOTQ2WhcNMzIwODI5MDMyOTQ2WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" +
+ "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" +
+ "DBNDRkNBIFRFU1QgQ1MgU00yIENBMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" +
+ "tTjB3O4JueYFDDOtxH678HBZbEmrsgd3BDIdGf0BekyA26n9S0/pKPnjBh/zLouS\n" +
+ "8+GB5EEnjbn4An24yo1Gv6NdMFswHwYDVR0jBBgwFoAUtdiQb1zw2DPSY71+ssON\n" +
+ "xk8SemEwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFLXYkG9c\n" +
+ "8Ngz0mO9frLDjcZPEnphMAwGCCqBHM9VAYN1BQADSQAwRgIhAKwuuqoBS1bwDowW\n" +
+ "a4IU//UsvudswJYSlltqrd/PQ9q+AiEAyTUAjFdaGI+8yPdr3A93UiA38wtGPf9e\n" +
+ "6B6O/6abyWE=\n" +
+ "-----END CERTIFICATE-----";
+
+ String issuerCert = "-----BEGIN CERTIFICATE-----\n" +
+ "MIICTzCCAfOgAwIBAgIKJFSZ4SRVDndYUTAMBggqgRzPVQGDdQUAMF0xCzAJBgNV\n" +
+ "BAYTAkNOMTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBB\n" +
+ "dXRob3JpdHkxHDAaBgNVBAMME0NGQ0EgVEVTVCBDUyBTTTIgQ0EwHhcNMTIwODI5\n" +
+ "MDU0ODQ3WhcNMzIwODI0MDU0ODQ3WjBdMQswCQYDVQQGEwJDTjEwMC4GA1UECgwn\n" +
+ "Q2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRwwGgYDVQQD\n" +
+ "DBNDRkNBIFRFU1QgU00yIE9DQTExMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE\n" +
+ "L1mx4wriQUojGsIkNL14kslv9nwiqsiVpELOZauzghrbccNlPYKNYKZOCvXwIIqU\n" +
+ "9QY02d4weqKqo/JMcNsKEaOBmDCBlTAfBgNVHSMEGDAWgBS12JBvXPDYM9JjvX6y\n" +
+ "w43GTxJ6YTAMBgNVHRMEBTADAQH/MDgGA1UdHwQxMC8wLaAroCmGJ2h0dHA6Ly8y\n" +
+ "MTAuNzQuNDIuMy90ZXN0cmNhL1NNMi9jcmwxLmNybDALBgNVHQ8EBAMCAQYwHQYD\n" +
+ "VR0OBBYEFL6mfk09fI+gVebBLwkuLCBDs0J/MAwGCCqBHM9VAYN1BQADSAAwRQIh\n" +
+ "AKuk7s3eYCZDck5NWU0eNQmLhBN/1zmKs517qFrDrkJWAiAP4cVfLtdza/OkwU9P\n" +
+ "PrIDl+E4aL3FypntFXHG3T+Keg==\n" +
+ "-----END CERTIFICATE-----";
+ parser.parse(issuerCert, CACert);
+ assertEquals("SM3WITHSM2",parser.getSigAlgName());
+ }
+}
diff --git a/source/crypto/pom.xml b/source/crypto/pom.xml
index fb6e71ba..f8b66416 100644
--- a/source/crypto/pom.xml
+++ b/source/crypto/pom.xml
@@ -16,6 +16,7 @@
crypto-sm
crypto-adv
+ crypto-pki
\ No newline at end of file
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
index 71e34a7c..1a6c0267 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
@@ -81,7 +81,7 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {
ledgerInitSettings.setSeed(initSeed(ledgerMetadata.getSeed()));
// 璁剧疆鍏辫瘑鍗忚
- ledgerInitSettings.setConsensusProtocol(consensusProtocol(ledgerMetadata.getSetting().getConsensusProvider()));
+ ledgerInitSettings.setConsensusProtocol(ledgerMetadata.getSetting().getConsensusProvider());
return ledgerInitSettings;
}
@@ -110,24 +110,6 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {
return seed.toString();
}
- /**
- * 鐢熸垚鍏辫瘑鍗忚
- *
- * @param consensusProvider
- * 鍏辫瘑鍗忚鎻愭彁渚涜
- * @return
- */
- private int consensusProtocol(String consensusProvider) {
-
- if (consensusProvider.equals(BftsmartConsensusProvider.NAME)) {
- return LedgerInitSettings.CONSENSUS_PROTOCOL.BFTSMART.code();
- } else if (consensusProvider.equals(MsgQueueConsensusProvider.NAME)) {
- return LedgerInitSettings.CONSENSUS_PROTOCOL.MSGQUEUE.code();
- }
-
- return LedgerInitSettings.CONSENSUS_PROTOCOL.UNKNOWN.code();
- }
-
/**
* 鍒濆鍖栧叡璇嗛厤缃
*
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
index 381cc50f..66f94b97 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
@@ -239,6 +239,13 @@ public class BlockBrowserController implements BlockchainExtendQueryService {
return peerService.getQueryService().getDataEntries(ledgerHash, address, keys);
}
+ @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version")
+ public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash,
+ @PathVariable("address") String address,
+ @RequestBody KVInfoVO kvInfoVO) {
+ return peerService.getQueryService().getDataEntries(ledgerHash, address, kvInfoVO);
+ }
+
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries")
@Override
public KVDataEntry[] getDataEntries(@PathVariable("ledgerHash") HashDigest ledgerHash,
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java
index b93a8008..4481088f 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/GatewayWebServerConfigurer.java
@@ -2,6 +2,13 @@ package com.jd.blockchain.gateway.web;
import java.util.List;
+import com.jd.blockchain.binaryproto.DataContractRegistry;
+import com.jd.blockchain.consensus.ClientIdentification;
+import com.jd.blockchain.consensus.ClientIdentifications;
+import com.jd.blockchain.consensus.action.ActionRequest;
+import com.jd.blockchain.consensus.action.ActionResponse;
+import com.jd.blockchain.consensus.bftsmart.BftsmartNodeSettings;
+import com.jd.blockchain.ledger.*;
import com.jd.blockchain.web.serializes.ByteArrayObjectUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
@@ -27,6 +34,7 @@ public class GatewayWebServerConfigurer implements WebMvcConfigurer {
static {
JSONSerializeUtils.disableCircularReferenceDetect();
JSONSerializeUtils.configStringSerializer(ByteArray.class);
+ DataContractRegistry.register(BftsmartNodeSettings.class);
}
diff --git a/source/gateway/src/main/resources/gateway.conf b/source/gateway/src/main/resources/gateway.conf
index c8ceaf4e..c0caa7c9 100644
--- a/source/gateway/src/main/resources/gateway.conf
+++ b/source/gateway/src/main/resources/gateway.conf
@@ -21,10 +21,10 @@ peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider
data.retrieval.url=http://127.0.0.1:10001
#榛樿鍏挜鐨勫唴瀹癸紙Base58缂栫爜鏁版嵁锛夛紱
-keys.default.pubkey=3snPdw7i7PapsDoW185c3kfK6p8s6SwiJAdEUzgnfeuUox12nxgzXu
+keys.default.pubkey=3snPdw7i7PjVKiTH2VnXZu5H8QmNaSXpnk4ei533jFpuifyjS5zzH9
#榛樿绉侀挜鐨勮矾寰勶紱鍦 pk-path 鍜 pk 涔嬮棿蹇呴』璁剧疆鍏朵竴锛
keys.default.privkey-path=
#榛樿绉侀挜鐨勫唴瀹癸紙鍔犲瘑鐨凚ase58缂栫爜鏁版嵁锛夛紱鍦 pk-path 鍜 pk 涔嬮棿蹇呴』璁剧疆鍏朵竴锛
-keys.default.privkey=177gjyoEUhdD1NkQSxBVvfSyovMd1ha5H46zsb9kyErLNBuQkLRAf2ea6CNjStjCFJQN8S1
+keys.default.privkey=177gjzHTznYdPgWqZrH43W3yp37onm74wYXT4v9FukpCHBrhRysBBZh7Pzdo5AMRyQGJD7x
#榛樿绉侀挜鐨勮В鐮佸瘑鐮侊紱
keys.default.privkey-password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY
\ No newline at end of file
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
index aa51901a..0655cb24 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccount.java
@@ -157,6 +157,9 @@ public class DataAccount implements AccountHeader, MerkleProvable {
* @return return total count;
*/
public long getDataEntriesTotalCount() {
+ if(baseAccount == null){
+ return 0;
+ }
return baseAccount.dataset.getDataCount();
}
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java
index 086b18ff..fba47095 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerQueryService.java
@@ -2,6 +2,7 @@ package com.jd.blockchain.ledger.core.impl;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.PrimitiveType;
+import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.ContractAccountSet;
@@ -15,6 +16,10 @@ import com.jd.blockchain.ledger.core.UserAccountSet;
import com.jd.blockchain.transaction.BlockchainQueryService;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.QueryUtil;
+import com.jd.blockchain.utils.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
public class LedgerQueryService implements BlockchainQueryService {
@@ -263,6 +268,9 @@ public class LedgerQueryService implements BlockchainQueryService {
long ver;
for (int i = 0; i < entries.length; i++) {
ver = dataAccount.getDataVersion(Bytes.fromString(keys[i]));
+
+ dataAccount.getBytes(Bytes.fromString(keys[i]),1);
+
if (ver < 0) {
entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null);
}else {
@@ -275,6 +283,60 @@ public class LedgerQueryService implements BlockchainQueryService {
return entries;
}
+ public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) {
+ //parse kvInfoVO;
+ List keyList = new ArrayList<>();
+ List versionList = new ArrayList<>();
+ if(kvInfoVO != null){
+ for(KVDataVO kvDataVO : kvInfoVO.getData()){
+ for(Long version : kvDataVO.getVersion()){
+ keyList.add(kvDataVO.getKey());
+ versionList.add(version);
+ }
+ }
+ }
+ String[] keys = keyList.toArray(new String[keyList.size()]);
+ Long[] versions = versionList.toArray(new Long[versionList.size()]);
+
+ if (keys == null || keys.length == 0) {
+ return null;
+ }
+ if (versions == null || versions.length == 0) {
+ return null;
+ }
+ if(keys.length != versions.length){
+ throw new ContractException("keys.length!=versions.length!");
+ }
+
+ LedgerRepository ledger = ledgerService.getLedger(ledgerHash);
+ LedgerBlock block = ledger.getLatestBlock();
+ DataAccountSet dataAccountSet = ledger.getDataAccountSet(block);
+ DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address));
+
+ KVDataEntry[] entries = new KVDataEntry[keys.length];
+ long ver = -1;
+ for (int i = 0; i < entries.length; i++) {
+// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i]));
+// dataAccount.getBytes(Bytes.fromString(keys[i]),1);
+ ver = versions[i];
+ if (ver < 0) {
+ entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null);
+ }else {
+ if(dataAccount.getDataEntriesTotalCount()==0 ||
+ dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null){
+ //is the address is not exist; the result is null;
+ entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null);
+ } else {
+ byte[] value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver);
+ BytesValue decodeData = BinaryProtocol.decode(value);
+ entries[i] = new KVDataObject(keys[i], ver, PrimitiveType.valueOf(decodeData.getType().CODE), decodeData.getValue().toBytes());
+ }
+ }
+ }
+
+ return entries;
+ }
+
@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) {
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
index 2d51c185..43595152 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
@@ -156,6 +156,11 @@ public class ContractLedgerContext implements LedgerContext {
return innerQueryService.getDataEntries(ledgerHash, address, keys);
}
+ @Override
+ public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) {
+ return innerQueryService.getDataEntries(ledgerHash, address, kvInfoVO);
+ }
+
@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) {
return innerQueryService.getDataEntries(ledgerHash, address, fromIndex, count);
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java
new file mode 100644
index 00000000..4fc214d0
--- /dev/null
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVDataVO.java
@@ -0,0 +1,26 @@
+package com.jd.blockchain.ledger;
+
+/**
+ * @author zhaogw
+ * date 2019/5/14 14:17
+ */
+public class KVDataVO {
+ private String key;
+ private long[] version;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public long[] getVersion() {
+ return version;
+ }
+
+ public void setVersion(long[] version) {
+ this.version = version;
+ }
+}
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java
new file mode 100644
index 00000000..5f49e3de
--- /dev/null
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/KVInfoVO.java
@@ -0,0 +1,18 @@
+package com.jd.blockchain.ledger;
+
+/**
+ * for BlockBrowserController.java, param is json ,then match it;
+ * @author zhaogw
+ * date 2019/5/14 14:19
+ */
+public class KVInfoVO {
+ private KVDataVO[] data;
+
+ public KVDataVO[] getData() {
+ return data;
+ }
+
+ public void setData(KVDataVO[] data) {
+ this.data = data;
+ }
+}
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantNode.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantNode.java
index c8974d1c..dd2c62fa 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantNode.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ParticipantNode.java
@@ -22,6 +22,7 @@ public interface ParticipantNode {// extends ConsensusNode, ParticipantInfo {
*
* @return
*/
+ @DataField(order = 0, primitiveType = PrimitiveType.INT32)
int getId();
/**
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
index f32f2cc1..e89d41b6 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionState.java
@@ -29,6 +29,11 @@ public enum TransactionState {
*/
LEDGER_ERROR((byte) 2),
+ /**
+ * 鏁版嵁搴忓垪鏇存柊閿欒锛
+ */
+ DATA_SEQUENCE_UPDATE_ERROR((byte) 3),
+
/**
* 绯荤粺閿欒锛
*/
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
index 45301f13..1b46f1aa 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
@@ -261,6 +261,8 @@ public interface BlockchainQueryService {
*/
KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys);
+ KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO);
+
/**
* 杩斿洖鎸囧畾鏁版嵁璐︽埛涓璌V鏁版嵁鐨勬绘暟锛
*
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
index c9b97e4d..00495bdb 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/ContractInvocationProxy.java
@@ -1,22 +1,53 @@
package com.jd.blockchain.transaction;
+import com.jd.blockchain.utils.Bytes;
+import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils;
+
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-public class ContractInvocationProxy implements InvocationHandler {
-
-
- private String contractMessage;
-
+public class ContractInvocationProxy implements InvocationHandler {
+
+ // private String contractMessage;
+
+ private Bytes contractAddress;
+
+ private ContractType contractType;
private ContractEventSendOperationBuilder sendOpBuilder;
-
-
+
+ public ContractInvocationProxy(Bytes contractAddress, ContractType contractType,
+ ContractEventSendOperationBuilder sendOpBuilder) {
+ this.contractAddress = contractAddress;
+ this.contractType = contractType;
+ this.sendOpBuilder = sendOpBuilder;
+ }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // TODO Auto-generated method stub
+
+ if(contractType == null){
+ return "contractType == null, no invoke really.";
+ }
+
+ String event = contractType.getEvent(method);
+ if (event == null) {
+ // 閫傞厤 Object 瀵硅薄鐨勬柟娉曪紱
+ // toString 鏂规硶锛
+ return String.format("[%s]-%s", contractAddress, contractType.toString());
+
+ // hashCode 鏂规硶锛
+ }
+ // 鍚堢害鏂规硶锛
+ byte[] argBytes = serializeArgs(args);
+ sendOpBuilder.send(contractAddress, event, argBytes);
+
+ // TODO: 鏆傛椂鏈冭檻鏈夎繑鍥炲肩殑鎯呭喌锛
return null;
}
+ private byte[] serializeArgs(Object[] args) {
+ // TODO 鏍规嵁鏂规硶鍙傛暟鐨勫畾涔夊簭鍒楀寲鍙傛暟锛
+ return BinarySerializeUtils.serialize(args);
+ }
}
diff --git a/source/peer/pom.xml b/source/peer/pom.xml
index 01311d5c..51746e7d 100644
--- a/source/peer/pom.xml
+++ b/source/peer/pom.xml
@@ -20,6 +20,11 @@
consensus-framework
${project.version}
+
+ com.jd.blockchain
+ state-transfer
+ ${project.version}
+
com.jd.blockchain
ledger-rpc
diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceReaderImpl.java b/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceReaderImpl.java
new file mode 100644
index 00000000..71161411
--- /dev/null
+++ b/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceReaderImpl.java
@@ -0,0 +1,132 @@
+//package com.jd.blockchain.peer.statetransfer;
+//
+//import com.jd.blockchain.binaryproto.BinaryEncodingUtils;
+//import com.jd.blockchain.crypto.hash.HashDigest;
+//import com.jd.blockchain.ledger.LedgerBlock;
+//import com.jd.blockchain.ledger.LedgerTransaction;
+//import com.jd.blockchain.ledger.core.LedgerManage;
+//import com.jd.blockchain.ledger.core.LedgerRepository;
+//import com.jd.blockchain.ledger.core.TransactionSet;
+//import com.jd.blockchain.statetransfer.DataSequenceElement;
+//import com.jd.blockchain.statetransfer.DataSequenceInfo;
+//import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+//import com.jd.blockchain.storage.service.DbConnection;
+//import com.jd.blockchain.storage.service.DbConnectionFactory;
+//import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
+//import com.jd.blockchain.utils.codec.Base58Utils;
+//import com.jd.blockchain.utils.codec.HexUtils;
+//import org.springframework.beans.factory.annotation.Autowired;
+//
+///**
+// *鏁版嵁搴忓垪宸紓鐨勬彁渚涜呴渶瑕佷娇鐢ㄧ殑鍥炶皟鎺ュ彛瀹炵幇绫
+// * @author zhangshuang
+// * @create 2019/4/11
+// * @since 1.0.0
+// */
+//public class DataSequenceReaderImpl implements DataSequenceReader {
+//
+// private LedgerManage ledgerManager;
+//
+// private DbConnectionFactory connFactory;
+//
+// private LedgerBindingConfig config;
+//
+// public DataSequenceReaderImpl(LedgerBindingConfig config, LedgerManage ledgerManager, DbConnectionFactory connFactory) {
+// this.config = config;
+// this.ledgerManager = ledgerManager;
+// this.connFactory = connFactory;
+// }
+//
+//
+// /**
+// * @param id 璐︽湰鍝堝笇鐨凚ase58缂栫爜
+// * @return DataSequenceInfo 鏁版嵁搴忓垪淇℃伅
+// */
+// @Override
+// public DataSequenceInfo getDSInfo(String id) {
+//
+// byte[] hashBytes = Base58Utils.decode(id);
+//
+// HashDigest ledgerHash = new HashDigest(hashBytes);
+//
+// LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash);
+// DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(),
+// bindingConfig.getDbConnection().getPassword());
+// LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService());
+//
+// return new DataSequenceInfo(id, ledgerRepository.getLatestBlockHeight());
+// }
+//
+// /**
+// *
+// * @param id 璐︽湰鍝堝笇鐨凚ase58缂栫爜
+// * @param from 鏁版嵁搴忓垪澶嶅埗鐨勮捣濮嬮珮搴
+// * @param to 鏁版嵁搴忓垪澶嶅埗鐨勭粨鏉熼珮搴
+// * @return DataSequenceElement銆愩戞暟鎹簭鍒楀樊寮傛暟鎹厓绱犵殑鏁扮粍
+// */
+// @Override
+// public DataSequenceElement[] getDSDiffContent(String id, long from, long to) {
+//
+// DataSequenceElement[] dataSequenceElements = new DataSequenceElement[(int)(to - from + 1)];
+// for (long i = from; i < to + 1; i++) {
+// dataSequenceElements[(int)(i - from)] = getDSDiffContent(id, i);
+// }
+//
+// return dataSequenceElements;
+// }
+//
+// /**
+// * 璐︽湰浜ゆ槗搴忓垪鍖
+// * @param transaction 璐︽湰浜ゆ槗
+// * @return byte[] 瀵硅处鏈氦鏄撹繘琛屽簭鍒楀寲鐨勭粨鏋
+// */
+// private byte[] serialize(LedgerTransaction transaction) {
+// return BinaryEncodingUtils.encode(transaction, LedgerTransaction.class);
+// }
+//
+// /**
+// * 鑾峰緱璐︽湰鏌愪竴楂樺害鍖哄潡涓婄殑鎵鏈変氦鏄
+// * @param id 璐︽湰鍝堝笇鐨凚ase58缂栫爜
+// * @param height 璐︽湰鐨勬煇涓尯鍧楅珮搴
+// * @return DataSequenceElement 鏁版嵁搴忓垪宸紓鏁版嵁鍏冪礌
+// */
+// @Override
+// public DataSequenceElement getDSDiffContent(String id, long height) {
+//
+// int lastHeightTxTotalNums = 0;
+//
+// byte[][] transacionDatas = null;
+//
+// byte[] hashBytes = Base58Utils.decode(id);
+//
+// HashDigest ledgerHash = new HashDigest(hashBytes);
+//
+// LedgerBindingConfig.BindingConfig bindingConfig = config.getLedger(ledgerHash);
+// DbConnection dbConnNew = connFactory.connect(bindingConfig.getDbConnection().getUri(),
+// bindingConfig.getDbConnection().getPassword());
+// LedgerRepository ledgerRepository = ledgerManager.register(ledgerHash, dbConnNew.getStorageService());
+//
+// LedgerBlock ledgerBlock = ledgerRepository.getBlock(height);
+// TransactionSet transactionSet = ledgerRepository.getTransactionSet(ledgerBlock);
+//
+// if (height > 0) {
+// lastHeightTxTotalNums = (int) ledgerRepository.getTransactionSet(ledgerRepository.getBlock(height - 1)).getTotalCount();
+// }
+//
+// int currentHeightTxTotalNums = (int)ledgerRepository.getTransactionSet(ledgerRepository.getBlock(height)).getTotalCount();
+//
+// // get all transactions from current height block
+// int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums;
+//
+// LedgerTransaction[] transactions = transactionSet.getTxs(lastHeightTxTotalNums , currentHeightTxNums);
+//
+// for (int i = 0; i < transactions.length; i++) {
+// byte[] transactionData = serialize(transactions[i]);
+// transacionDatas[i] = transactionData;
+// }
+//
+// return new DataSequenceElement(id, height, transacionDatas);
+// }
+//
+//
+//}
diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceWriterImpl.java b/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceWriterImpl.java
new file mode 100644
index 00000000..774e69b5
--- /dev/null
+++ b/source/peer/src/main/java/com/jd/blockchain/peer/statetransfer/DataSequenceWriterImpl.java
@@ -0,0 +1,170 @@
+//package com.jd.blockchain.peer.statetransfer;
+//
+//import com.jd.blockchain.consensus.service.MessageHandle;
+//import com.jd.blockchain.ledger.TransactionState;
+//import com.jd.blockchain.statetransfer.DataSequenceElement;
+//import com.jd.blockchain.statetransfer.DataSequenceInfo;
+//import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+//import com.jd.blockchain.statetransfer.comparator.DataSequenceComparator;
+//
+//import java.util.ArrayList;
+//import java.util.Collections;
+//
+///**
+// *鏁版嵁搴忓垪宸紓鐨勮姹傝呴渶瑕佷娇鐢ㄧ殑鍥炶皟鎺ュ彛瀹炵幇绫
+// * @author zhangshuang
+// * @create 2019/4/11
+// * @since 1.0.0
+// */
+//public class DataSequenceWriterImpl implements DataSequenceWriter {
+//
+// private long currHeight;
+// private ArrayList deceidedElements = new ArrayList();
+//
+// private MessageHandle batchMessageHandle;
+//
+//
+// public DataSequenceWriterImpl(MessageHandle batchMessageHandle) {
+// this.batchMessageHandle = batchMessageHandle;
+// }
+//
+// /**
+// * 妫鏌ユ暟鎹簭鍒楀樊寮傚厓绱犱腑鐨勯珮搴︽槸鍚﹀悎鐞嗭紱
+// * @param currHeight 褰撳墠缁撶偣鐨勮处鏈珮搴
+// * @param dsUpdateElements 闇瑕佹洿鏂板埌鏈湴缁撶偣鐨勬暟鎹簭鍒楀厓绱燣ist
+// * @return
+// */
+// private int checkElementsHeight(long currHeight, ArrayList dsUpdateElements) {
+// boolean lossMiddleElements = false;
+//
+// // lose first element
+// if (currHeight + 1 < dsUpdateElements.get(0).getHeight()){
+// System.out.println("Diff response loss first element error!");
+// return DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE;
+// }
+// else {
+// for (int i = 0; i < dsUpdateElements.size(); i++) {
+// if (dsUpdateElements.get(i).getHeight() == currHeight + 1 + i) {
+// deceidedElements.add(dsUpdateElements.get(i));
+// }
+// // lose middle elements
+// else {
+// lossMiddleElements = true;
+// break;
+// }
+// }
+//
+// if (lossMiddleElements) {
+// System.out.println("Diff response loss middle elements error!");
+// return DataSequenceErrorType.DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT.CODE;
+// }
+//
+// System.out.println("Diff response elements height normal!");
+// return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE;
+// }
+//
+// }
+//
+// /**
+// * 瀵规湰鍦扮粨鐐规墽琛岃处鏈洿鏂
+// * @param realmName 璐︽湰鍝堝笇鐨凚ase58缂栫爜
+// * @return void
+// */
+// private void exeUpdate(String realmName) {
+//
+// for (int i = 0; i < deceidedElements.size(); i++) {
+// byte[][] element = deceidedElements.get(i).getData();
+//
+// String batchId = batchMessageHandle.beginBatch(realmName);
+// try {
+// int msgId = 0;
+// for (byte[] txContent : element) {
+// batchMessageHandle.processOrdered(msgId++, txContent, realmName, batchId);
+// }
+// // 缁撳潡
+// batchMessageHandle.completeBatch(realmName, batchId);
+// batchMessageHandle.commitBatch(realmName, batchId);
+// } catch (Exception e) {
+// // todo 闇瑕佸鐞嗗簲绛旂爜 404
+// batchMessageHandle.rollbackBatch(realmName, batchId, TransactionState.DATA_SEQUENCE_UPDATE_ERROR.CODE);
+// }
+// }
+//
+// }
+//
+// /**
+// * @param dsInfo 褰撳墠缁撶偣鐨勬暟鎹簭鍒椾俊鎭
+// * @param diffContents 鏁版嵁搴忓垪宸紓鐨勬暟鎹厓绱犳暟缁
+// * @return int 鏇存柊缁撴灉鐮
+// */
+// @Override
+// public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents) {
+// int result = 0;
+//
+// try {
+// ArrayList dsUpdateElements = new ArrayList();
+// //remove unexpected elements
+// for (int i = 0 ; i < diffContents.length; i++) {
+// if (diffContents[i].getId().equals(dsInfo.getId())) {
+// dsUpdateElements.add(diffContents[i]);
+// }
+// }
+//
+// // sort elements by height
+// Collections.sort(dsUpdateElements, new DataSequenceComparator());
+//
+// currHeight = dsInfo.getHeight();
+//
+// // check element's height
+// result = checkElementsHeight(currHeight, dsUpdateElements);
+//
+// // cann't exe update
+// if (result == DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE) {
+// return result;
+// }
+// // exe elements update
+// else {
+// exeUpdate(dsInfo.getId());
+// return result;
+// }
+// } catch (Exception e) {
+// System.out.println(e.getMessage());
+// e.printStackTrace();
+// }
+//
+// return result;
+// }
+//
+// @Override
+// public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContents) {
+// return 0;
+// }
+//
+//
+// /**
+// * 鏁版嵁搴忓垪鏇存柊閿欒鐮
+// * @param
+// * @return
+// */
+// public enum DataSequenceErrorType {
+// DATA_SEQUENCE_LOSS_FIRST_ELEMENT((byte) 0x1),
+// DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT((byte) 0x2),
+// DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL((byte) 0x3),
+// ;
+// public final int CODE;
+//
+// private DataSequenceErrorType(byte code) {
+// this.CODE = code;
+// }
+//
+// public static DataSequenceErrorType valueOf(byte code) {
+// for (DataSequenceErrorType errorType : DataSequenceErrorType.values()) {
+// if (errorType.CODE == code) {
+// return errorType;
+// }
+// }
+// throw new IllegalArgumentException("Unsupported code[" + code + "] of errorType!");
+// }
+// }
+//
+//}
diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java
index 6db9674c..222d7bf6 100644
--- a/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java
+++ b/source/peer/src/main/java/com/jd/blockchain/peer/web/LedgerQueryController.java
@@ -1,21 +1,30 @@
package com.jd.blockchain.peer.web;
+import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.ledger.*;
-import com.jd.blockchain.ledger.core.*;
+import com.jd.blockchain.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import com.jd.blockchain.binaryproto.BinaryProtocol;
import com.jd.blockchain.binaryproto.PrimitiveType;
import com.jd.blockchain.crypto.HashDigest;
+import com.jd.blockchain.ledger.core.ContractAccountSet;
+import com.jd.blockchain.ledger.core.DataAccount;
+import com.jd.blockchain.ledger.core.DataAccountSet;
+import com.jd.blockchain.ledger.core.LedgerAdministration;
+import com.jd.blockchain.ledger.core.LedgerRepository;
+import com.jd.blockchain.ledger.core.LedgerService;
+import com.jd.blockchain.ledger.core.ParticipantCertData;
+import com.jd.blockchain.ledger.core.TransactionSet;
+import com.jd.blockchain.ledger.core.UserAccountSet;
import com.jd.blockchain.transaction.BlockchainQueryService;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.QueryUtil;
+import java.util.ArrayList;
+import java.util.List;
+
@RestController
@RequestMapping(path = "/")
public class LedgerQueryController implements BlockchainQueryService {
@@ -342,6 +351,63 @@ public class LedgerQueryController implements BlockchainQueryService {
return entries;
}
+ @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/{address}/entries-version")
+ @Override
+ public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
+ @PathVariable(name = "address") String address,
+ @RequestBody KVInfoVO kvInfoVO) {
+ //parse kvInfoVO;
+ List keyList = new ArrayList<>();
+ List versionList = new ArrayList<>();
+ if(kvInfoVO != null){
+ for(KVDataVO kvDataVO : kvInfoVO.getData()){
+ for(Long version : kvDataVO.getVersion()){
+ keyList.add(kvDataVO.getKey());
+ versionList.add(version);
+ }
+ }
+ }
+ String[] keys = keyList.toArray(new String[keyList.size()]);
+ Long[] versions = versionList.toArray(new Long[versionList.size()]);
+
+ if (keys == null || keys.length == 0) {
+ return null;
+ }
+ if (versions == null || versions.length == 0) {
+ return null;
+ }
+ if(keys.length != versions.length){
+ throw new ContractException("keys.length!=versions.length!");
+ }
+
+ LedgerRepository ledger = ledgerService.getLedger(ledgerHash);
+ LedgerBlock block = ledger.getLatestBlock();
+ DataAccountSet dataAccountSet = ledger.getDataAccountSet(block);
+ DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address));
+
+ KVDataEntry[] entries = new KVDataEntry[keys.length];
+ long ver = -1;
+ for (int i = 0; i < entries.length; i++) {
+// ver = dataAccount.getDataVersion(Bytes.fromString(keys[i]));
+ ver = versions[i];
+ if (ver < 0) {
+ entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null);
+ }else {
+ if(dataAccount.getDataEntriesTotalCount()==0 ||
+ dataAccount.getBytes(Bytes.fromString(keys[i]), ver) == null){
+ //is the address is not exist; the result is null;
+ entries[i] = new KVDataObject(keys[i], -1, PrimitiveType.NIL, null);
+ } else {
+ byte[] value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver);
+ BytesValue decodeData = BinaryProtocol.decode(value);
+ entries[i] = new KVDataObject(keys[i], ver, PrimitiveType.valueOf(decodeData.getType().CODE), decodeData.getValue().toBytes());
+ }
+ }
+ }
+
+ return entries;
+ }
+
@RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries")
@Override
public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
diff --git a/source/peer/src/main/java/com/jd/blockchain/peer/web/PeerTimeTasks.java b/source/peer/src/main/java/com/jd/blockchain/peer/web/PeerTimeTasks.java
index 8e3d220f..698fb584 100644
--- a/source/peer/src/main/java/com/jd/blockchain/peer/web/PeerTimeTasks.java
+++ b/source/peer/src/main/java/com/jd/blockchain/peer/web/PeerTimeTasks.java
@@ -15,11 +15,11 @@ import com.jd.blockchain.peer.ConsensusManage;
import com.jd.blockchain.peer.LedgerBindingConfigAware;
import com.jd.blockchain.peer.PeerServerBooter;
import com.jd.blockchain.tools.initializer.LedgerBindingConfig;
-import com.jd.blockchain.utils.ArgumentSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.ClassPathResource;
@@ -38,9 +38,11 @@ import java.util.*;
* @since 1.0.0
*/
@Component
-//@EnableScheduling
+@EnableScheduling
public class PeerTimeTasks implements ApplicationContextAware {
+ private static Logger LOGGER = LoggerFactory.getLogger(PeerTimeTasks.class);
+
private ApplicationContext applicationContext;
@Autowired
@@ -51,7 +53,9 @@ public class PeerTimeTasks implements ApplicationContextAware {
//姣1鍒嗛挓鎵ц涓娆
@Scheduled(cron = "0 */5 * * * * ")
public void updateLedger(){
- System.out.println ("Update Ledger Tasks Start " + new Date());
+
+ LOGGER.debug("Time Task Update Ledger Tasks Start {}", new Date());
+
try {
LedgerBindingConfig ledgerBindingConfig = loadLedgerBindingConfig();
@@ -78,7 +82,8 @@ public class PeerTimeTasks implements ApplicationContextAware {
Map bindingConfigAwares = applicationContext.getBeansOfType(LedgerBindingConfigAware.class);
List nodeServers = new ArrayList<>();
for (HashDigest ledgerHash : newAddHashs) {
- System.out.printf("newLedger[%s] \r\n", ledgerHash.toBase58());
+
+ LOGGER.info("New Ledger [{}] Need To Be Init !!!", ledgerHash.toBase58());
for (LedgerBindingConfigAware aware : bindingConfigAwares.values()) {
nodeServers.add(aware.setConfig(ledgerBindingConfig, ledgerHash));
}
@@ -89,10 +94,10 @@ public class PeerTimeTasks implements ApplicationContextAware {
consensusManage.runRealm(nodeServer);
}
} else {
- System.out.println("All Ledgers is newest!!!");
+ LOGGER.debug("All Ledgers is newest!!!");
}
} catch (Exception e) {
- e.printStackTrace();
+ LOGGER.error(e.getMessage());
}
}
@@ -104,7 +109,8 @@ public class PeerTimeTasks implements ApplicationContextAware {
private LedgerBindingConfig loadLedgerBindingConfig() throws Exception {
LedgerBindingConfig ledgerBindingConfig;
ledgerBindConfigFile = PeerServerBooter.ledgerBindConfigFile;
- System.out.printf("load ledgerBindConfigFile = %s \r\n", ledgerBindConfigFile);
+ LOGGER.debug("Load LedgerBindConfigFile path = {}",
+ ledgerBindConfigFile == null ? "Default" : ledgerBindConfigFile);
if (ledgerBindConfigFile == null) {
ClassPathResource configResource = new ClassPathResource("ledger-binding.conf");
InputStream in = configResource.getInputStream();
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/LedgerInitSettings.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/LedgerInitSettings.java
index fa3c2cd0..d4f287ab 100644
--- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/LedgerInitSettings.java
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/LedgerInitSettings.java
@@ -34,7 +34,7 @@ public class LedgerInitSettings {
/**
* 鍏辫瘑鍗忚
*/
- private int consensusProtocol;
+ private String consensusProtocol;
/**
* 鍏辫瘑閰嶇疆
@@ -70,11 +70,11 @@ public class LedgerInitSettings {
this.cryptoSetting = cryptoSetting;
}
- public int getConsensusProtocol() {
+ public String getConsensusProtocol() {
return consensusProtocol;
}
- public void setConsensusProtocol(int consensusProtocol) {
+ public void setConsensusProtocol(String consensusProtocol) {
this.consensusProtocol = consensusProtocol;
}
@@ -93,21 +93,4 @@ public class LedgerInitSettings {
public void setParticipantNodes(ParticipantNode[] participantNodes) {
this.participantNodes = participantNodes;
}
-
- public enum CONSENSUS_PROTOCOL {
- UNKNOWN(0),
- BFTSMART(1),
- MSGQUEUE(2),
- ;
-
- private int code;
-
- CONSENSUS_PROTOCOL(int code) {
- this.code = code;
- }
-
- public int code() {
- return code;
- }
- }
}
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
index 4dbe7bc9..e18f1df7 100644
--- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
@@ -147,6 +147,11 @@ public abstract class BlockchainServiceProxy implements BlockchainService {
return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, keys);
}
+ @Override
+ public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, KVInfoVO kvInfoVO) {
+ return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, kvInfoVO);
+ }
+
@Override
public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) {
return getQueryService(ledgerHash).getDataEntries(ledgerHash, address, fromIndex, count);
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
index bfdc0baf..bd063a5d 100644
--- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
@@ -496,7 +496,11 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService
@PathParam(name="address") String address,
@RequestParam(name="keys", array = true) String... keys);
- @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries")
+ @HttpAction(method=HttpMethod.POST, path="ledgers/{ledgerHash}/accounts/{address}/entries-version")
+ @Override
+ KVDataEntry[] getDataEntries(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash,
+ @PathParam(name="address") String address,
+ @RequestBody KVInfoVO kvInfoVO);
/**
* 杩斿洖鏁版嵁璐︽埛涓寚瀹氬簭鍙风殑鏈鏂板硷紱
@@ -513,6 +517,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService
* 濡傛灉鍙傛暟鍊间负 -1锛屽垯杩斿洖鍏ㄩ儴鐨勮褰曪紱
* @return
*/
+ @HttpAction(method = HttpMethod.POST, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries")
@Override
KVDataEntry[] getDataEntries(@PathParam(name = "ledgerHash") HashDigest ledgerHash,
@PathParam(name = "address") String address,
diff --git a/source/state-transfer/pom.xml b/source/state-transfer/pom.xml
new file mode 100644
index 00000000..d17c8e03
--- /dev/null
+++ b/source/state-transfer/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+
+ com.jd.blockchain
+ jdchain-root
+ 0.9.0-SNAPSHOT
+
+ state-transfer
+
+
+
+ com.jd.blockchain
+ stp-communication
+ ${project.version}
+
+
+ com.jd.blockchain
+ utils-common
+ ${project.version}
+
+
+
+ com.jd.blockchain
+ utils-serialize
+ ${project.version}
+
+
+
+
+
+
+
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequence.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequence.java
new file mode 100644
index 00000000..237a6d47
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequence.java
@@ -0,0 +1,75 @@
+package com.jd.blockchain.statetransfer;
+
+import java.net.InetSocketAddress;
+import java.util.LinkedList;
+
+/**
+ * 娴嬭瘯杩囩▼寤虹珛鐨勪竴涓暟鎹簭鍒
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DataSequence {
+
+ private InetSocketAddress address;
+ private String id;
+
+ // 姣忎釜鏁版嵁搴忓垪缁存姢浜嗕竴绯诲垪鐨勬暟鎹簭鍒楀厓绱
+ private LinkedList dataSequenceElements = new LinkedList<>();
+
+
+ public DataSequence(InetSocketAddress address, String id) {
+ this.address = address;
+ this.id = id;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public InetSocketAddress getAddress() {
+ return address;
+ }
+
+
+ public void addElements(DataSequenceElement[] elements) {
+ for (DataSequenceElement element : elements) {
+ addElement(element);
+ }
+ }
+
+ public void addElement(DataSequenceElement element) {
+ try {
+ if (dataSequenceElements.size() == 0) {
+ if (element.getHeight() != 0) {
+ throw new IllegalArgumentException("Data sequence add element height error!");
+ }
+ dataSequenceElements.addLast(element);
+ }
+ else {
+ if (dataSequenceElements.getLast().getHeight() != element.getHeight() - 1) {
+ throw new IllegalArgumentException("Data sequence add element height error!");
+ }
+ dataSequenceElements.addLast(element);
+ }
+
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public LinkedList getDataSequenceElements() {
+ return dataSequenceElements;
+ }
+
+ public DataSequenceInfo getDSInfo() {
+ if (dataSequenceElements.size() == 0) {
+ return new DataSequenceInfo(id, -1);
+ }
+ else {
+ return new DataSequenceInfo(id, dataSequenceElements.getLast().getHeight());
+ }
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceElement.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceElement.java
new file mode 100644
index 00000000..aaf6e7f5
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceElement.java
@@ -0,0 +1,53 @@
+package com.jd.blockchain.statetransfer;
+
+import java.io.Serializable;
+
+/**
+ * 鏁版嵁搴忓垪闇瑕佸鍒跺唴瀹圭殑鍏冪礌鎴栧崟浣
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public class DataSequenceElement implements Serializable {
+
+ private static final long serialVersionUID = -719578198150380571L;
+
+ //鏁版嵁搴忓垪鐨勫敮涓鏍囪瘑绗︼紱
+ private String id;
+
+ //鏁版嵁搴忓垪鐨勬煇涓珮搴︼紱
+ private long height;
+
+ //瀵瑰簲鏌愪釜楂樺害鐨勬暟鎹簭鍒楀唴瀹
+ private byte[][] data;
+
+ public DataSequenceElement(String id, long height, byte[][] data) {
+ this.id = id;
+ this.height = height;
+ this.data = data;
+ }
+
+ public long getHeight() {
+ return height;
+ }
+
+ public void setHeight(long height) {
+ this.height = height;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ id = id;
+ }
+
+ public byte[][] getData() {
+ return data;
+ }
+
+ public void setData(byte[][] data) {
+ this.data = data;
+ }
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceInfo.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceInfo.java
new file mode 100644
index 00000000..6f0f2e10
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceInfo.java
@@ -0,0 +1,37 @@
+package com.jd.blockchain.statetransfer;
+
+/**
+ * 鍏辫瘑缁撶偣涓婄殑鏌愪釜鏁版嵁搴忓垪鐨勫綋鍓嶇姸鎬佷俊鎭紝姣忎釜鍏辫瘑缁撶偣鍙互瀵瑰簲浠绘剰涓暟鎹簭鍒楋紱
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public class DataSequenceInfo {
+
+ //鏁版嵁搴忓垪鐨勫敮涓鏍囪瘑
+ private String id;
+
+ //鏁版嵁搴忓垪鐨勫綋鍓嶉珮搴
+ private long height;
+
+ public DataSequenceInfo(String id, long height) {
+ this.id = id;
+ this.height = height;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public long getHeight() {
+ return height;
+ }
+
+ public void setHeight(long height) {
+ this.height = height;
+ }
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReader.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReader.java
new file mode 100644
index 00000000..e137b929
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReader.java
@@ -0,0 +1,39 @@
+package com.jd.blockchain.statetransfer.callback;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鎻愪緵鑰呴渶瑕佷娇鐢ㄧ殑鍥炶皟鎺ュ彛
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public interface DataSequenceReader {
+
+ /**
+ * 宸紓鎻愪緵鑰呮牴鎹暟鎹簭鍒楁爣璇嗙鑾峰彇鏁版嵁搴忓垪褰撳墠鐘舵侊紱
+ * @param id 鏁版嵁搴忓垪鏍囪瘑绗
+ * @return 鏁版嵁搴忓垪褰撳墠鐘舵佷俊鎭
+ */
+ DataSequenceInfo getDSInfo(String id);
+
+
+ /**
+ * 宸紓鎻愪緵鑰呮牴鎹暟鎹簭鍒楁爣璇嗙浠ュ強璧峰锛岀粨鏉熼珮搴︽彁渚涙暟鎹簭鍒楄鑼冨洿鐨勫樊寮傚唴瀹癸紱
+ * @param id 鏁版嵁搴忓垪鏍囪瘑绗
+ * @param from 宸紓鐨勮捣濮嬮珮搴
+ * @param to 宸紓鐨勭粨鏉熼珮搴
+ * @return 宸紓鍏冪礌缁勬垚鐨勬暟缁
+ */
+ DataSequenceElement[] getDSDiffContent(String id, long from, long to);
+
+
+ /**
+ * 宸紓鎻愪緵鑰呮牴鎹暟鎹簭鍒楁爣璇嗙浠ュ強楂樺害鎻愪緵鏁版嵁搴忓垪鐨勫樊寮傚唴瀹癸紱
+ * @param id 鏁版嵁搴忓垪鏍囪瘑绗
+ * @param height 瑕佽幏寰楀摢涓珮搴︾殑宸紓鍏冪礌
+ * @return 宸紓鍏冪礌
+ */
+ DataSequenceElement getDSDiffContent(String id, long height);
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReaderImpl.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReaderImpl.java
new file mode 100644
index 00000000..3d581b2d
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReaderImpl.java
@@ -0,0 +1,59 @@
+package com.jd.blockchain.statetransfer.callback;
+
+import com.jd.blockchain.statetransfer.DataSequence;
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+
+import java.util.LinkedList;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鐨勬彁渚涜呴渶瑕佷娇鐢ㄧ殑鍥炶皟鎺ュ彛瀹炵幇绫
+ * @author zhangshuang
+ * @create 2019/4/22
+ * @since 1.0.0
+ */
+
+public class DataSequenceReaderImpl implements DataSequenceReader {
+
+ DataSequence currDataSequence;
+
+ public DataSequenceReaderImpl(DataSequence currDataSequence) {
+ this.currDataSequence = currDataSequence;
+ }
+
+ @Override
+ public DataSequenceInfo getDSInfo(String id) {
+ return currDataSequence.getDSInfo();
+ }
+
+ @Override
+ public DataSequenceElement[] getDSDiffContent(String id, long from, long to) {
+ DataSequenceElement[] elements = new DataSequenceElement[(int)(to - from + 1)];
+
+ int i = 0;
+ LinkedList dataSequenceElements = currDataSequence.getDataSequenceElements();
+ for (DataSequenceElement element : dataSequenceElements) {
+ if (element.getHeight() < from || element.getHeight() > to) {
+ continue;
+ }
+ else {
+ elements[i++] = element;
+ }
+ }
+
+ return elements;
+
+ }
+
+ @Override
+ public DataSequenceElement getDSDiffContent(String id, long height) {
+ for(DataSequenceElement dataSequenceElement : currDataSequence.getDataSequenceElements()) {
+ if (dataSequenceElement.getHeight() == height) {
+ return dataSequenceElement;
+
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriter.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriter.java
new file mode 100644
index 00000000..b45eb3ac
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriter.java
@@ -0,0 +1,30 @@
+package com.jd.blockchain.statetransfer.callback;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+
+/**
+ * 鏁版嵁搴忓垪宸紓璇锋眰鑰呰幏寰楀樊寮傚唴瀹瑰悗闇瑕佸洖璋冭鎺ュ彛
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public interface DataSequenceWriter {
+
+ /**
+ * 宸紓璇锋眰鑰呮洿鏂版湰鍦版暟鎹簭鍒楃殑鐘舵,涓娆″彲浠ユ洿鏂板涓樊寮傚厓绱
+ * @param dsInfo 鏁版嵁搴忓垪褰撳墠鐘舵佷俊鎭
+ * @param diffContents 闇瑕佹洿鏂扮殑宸紓鍏冪礌鏁扮粍
+ * @return 鏇存柊缁撴灉缂栫爜
+ */
+ int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents);
+
+ /**
+ * 宸紓璇锋眰鑰呮洿鏂版湰鍦版暟鎹簭鍒楃殑鐘舵侊紝涓娆″彧鏇存柊涓涓樊寮傚厓绱
+ * @param dsInfo 鏁版嵁搴忓垪褰撳墠鐘舵佷俊鎭
+ * @param diffContent 闇瑕佹洿鏂扮殑宸紓鍏冪礌
+ * @return 鏇存柊缁撴灉缂栫爜
+ */
+// int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContent);
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriterImpl.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriterImpl.java
new file mode 100644
index 00000000..c510e843
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriterImpl.java
@@ -0,0 +1,142 @@
+package com.jd.blockchain.statetransfer.callback;
+
+import com.jd.blockchain.statetransfer.DataSequence;
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+
+import java.util.ArrayList;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鐨勮姹傝呴渶瑕佷娇鐢ㄧ殑鍥炶皟鎺ュ彛瀹炵幇绫
+ * @author zhangshuang
+ * @create 2019/4/22
+ * @since 1.0.0
+ */
+public class DataSequenceWriterImpl implements DataSequenceWriter {
+
+ private long currHeight;
+ private DataSequence currDataSequence;
+ private ArrayList deceidedElements = new ArrayList();
+
+ public DataSequenceWriterImpl(DataSequence currDataSequence) {
+ this.currDataSequence = currDataSequence;
+ }
+
+ /**
+ * 妫鏌ユ暟鎹簭鍒楀樊寮傚厓绱犱腑鐨勯珮搴︽槸鍚﹀悎鐞嗭紱
+ * @param currHeight 褰撳墠缁撶偣鐨勮处鏈珮搴
+ * @param dsUpdateElements 闇瑕佹洿鏂板埌鏈湴缁撶偣鐨勬暟鎹簭鍒楀厓绱燣ist
+ * @return
+ */
+ private int checkElementsHeight(long currHeight, ArrayList dsUpdateElements) {
+ boolean lossMiddleElements = false;
+
+ // lose first element
+ if (currHeight + 1 < dsUpdateElements.get(0).getHeight()){
+ System.out.println("Diff response loss first element error!");
+ return DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE;
+ }
+ else {
+ for (int i = 0; i < dsUpdateElements.size(); i++) {
+ if (dsUpdateElements.get(i).getHeight() == currHeight + 1 + i) {
+ deceidedElements.add(dsUpdateElements.get(i));
+ }
+ // lose middle elements
+ else {
+ lossMiddleElements = true;
+ break;
+ }
+ }
+
+ if (lossMiddleElements) {
+ System.out.println("Diff response loss middle elements error!");
+ return DataSequenceErrorType.DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT.CODE;
+ }
+
+ System.out.println("Diff response elements height normal!");
+ return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE;
+ }
+
+ }
+
+ @Override
+ public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement[] diffContents) {
+
+ int result = 0;
+
+ try {
+ ArrayList dsUpdateElements = new ArrayList();
+
+ if (diffContents == null) {
+ throw new IllegalArgumentException("Update diffContents is null!");
+ }
+
+ //remove unexpected elements
+ for (int i = 0 ; i < diffContents.length; i++) {
+ if (diffContents[i].getId().equals(dsInfo.getId())) {
+ dsUpdateElements.add(diffContents[i]);
+ }
+ }
+
+ currHeight = dsInfo.getHeight();
+
+ // check element's height
+ result = checkElementsHeight(currHeight, dsUpdateElements);
+
+ // cann't exe update
+ if (result == DataSequenceErrorType.DATA_SEQUENCE_LOSS_FIRST_ELEMENT.CODE) {
+ return result;
+ }
+ // exe elements update
+ else {
+ System.out.println("Old data sequence state: ");
+ System.out.println(" Current height = " + currDataSequence.getDataSequenceElements().getLast().getHeight());
+ currDataSequence.addElements(deceidedElements.toArray(new DataSequenceElement[deceidedElements.size()]));
+
+ System.out.println("Update diffContents is completed!");
+ System.out.println("New data sequence state: ");
+ System.out.println(" Current height = " + currDataSequence.getDataSequenceElements().getLast().getHeight());
+
+ return result;
+ }
+
+
+
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ }
+
+ return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE;
+
+ }
+
+// @Override
+// public int updateDSInfo(DataSequenceInfo dsInfo, DataSequenceElement diffContent) {
+// currDataSequence.addElement(diffContent);
+// return DataSequenceErrorType.DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL.CODE;
+// }
+
+ public enum DataSequenceErrorType {
+ DATA_SEQUENCE_LOSS_FIRST_ELEMENT((byte) 0x1),
+ DATA_SEQUENCE_LOSS_MIDDLE_ELEMENT((byte) 0x2),
+ DATA_SEQUENCE_ELEMENT_HEIGHT_NORMAL((byte) 0x3),
+ ;
+ public final int CODE;
+
+ private DataSequenceErrorType(byte code) {
+ this.CODE = code;
+ }
+
+ public static DataSequenceErrorType valueOf(byte code) {
+ for (DataSequenceErrorType errorType : DataSequenceErrorType.values()) {
+ if (errorType.CODE == code) {
+ return errorType;
+ }
+ }
+ throw new IllegalArgumentException("Unsupported code[" + code + "] of errorType!");
+ }
+ }
+
+}
+
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/comparator/DataSequenceComparator.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/comparator/DataSequenceComparator.java
new file mode 100644
index 00000000..9e0afbe5
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/comparator/DataSequenceComparator.java
@@ -0,0 +1,32 @@
+package com.jd.blockchain.statetransfer.comparator;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+
+import java.util.Comparator;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鍏冪礌鐨勯珮搴︽瘮杈冨櫒
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DataSequenceComparator implements Comparator {
+
+ // sort by data sequence height
+ /**
+ * 瀵瑰樊寮傚厓绱犳牴鎹珮搴﹀ぇ灏忔帓搴
+ * @param o1 宸紓鍏冪礌1
+ * @param o2 宸紓鍏冪礌2
+ * @return >0 or <0
+ */
+ @Override
+ public int compare(DataSequenceElement o1, DataSequenceElement o2) {
+ long height1;
+ long height2;
+
+ height1 = o1.getHeight();
+ height2 = o2.getHeight();
+
+ return (int) (height1 - height2);
+ }
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/exception/DataSequenceException.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/exception/DataSequenceException.java
new file mode 100644
index 00000000..5e6248c0
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/exception/DataSequenceException.java
@@ -0,0 +1,21 @@
+package com.jd.blockchain.statetransfer.exception;
+
+/**
+ * 鏁版嵁搴忓垪寮傚父澶勭悊
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DataSequenceException extends RuntimeException {
+
+ private static final long serialVersionUID = -4090881296855827889L;
+
+
+ public DataSequenceException(String message) {
+ super(message);
+ }
+ public DataSequenceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSDefaultMessageExecutor.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSDefaultMessageExecutor.java
new file mode 100644
index 00000000..6c67e8c8
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSDefaultMessageExecutor.java
@@ -0,0 +1,80 @@
+package com.jd.blockchain.statetransfer.message;
+
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+import com.jd.blockchain.statetransfer.process.DSTransferProcess;
+import com.jd.blockchain.statetransfer.result.DSDiffRequestResult;
+import com.jd.blockchain.stp.communication.MessageExecutor;
+import com.jd.blockchain.stp.communication.RemoteSession;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鎻愪緵鑰呬娇鐢紝瑙f瀽鏀跺埌鐨勫樊寮傝姹傛秷鎭苟浜х敓鍝嶅簲
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public class DSDefaultMessageExecutor implements MessageExecutor {
+
+ DataSequenceReader dsReader;
+ DataSequenceWriter dsWriter;
+
+ public DSDefaultMessageExecutor(DataSequenceReader dsReader, DataSequenceWriter dsWriter) {
+ this.dsReader = dsReader;
+ this.dsWriter = dsWriter;
+ }
+
+ /**
+ * 瀵圭姸鎬佹満澶嶅埗鐨勫樊寮傝姹傝繘琛屽搷搴
+ * @param key 璇锋眰娑堟伅鐨凨ey
+ * @param data 闇瑕佽В鐮佺殑瀛楄妭鏁扮粍
+ * @param session 鎸囧畾鍝嶅簲闇瑕佷娇鐢ㄧ殑鐩爣缁撶偣浼氳瘽
+ * @return 閰嶇疆涓鸿嚜鍔ㄥ搷搴旀椂锛岃繑鍥炲间负鍝嶅簲鐨勫瓧鑺傛暟缁勶紝閰嶇疆涓烘墜鍔ㄥ搷搴旀椂锛屼笉闇瑕佸叧娉ㄨ繑鍥炲
+ */
+
+ @Override
+ public byte[] receive(String key, byte[] data, RemoteSession session) {
+
+ try {
+ Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(data);
+
+ // 瑙f瀽CMD_DSINFO_REQUEST 璇锋眰鐨勬儏鍐
+ if (object instanceof String) {
+ String id = (String)object;
+ byte[] respLoadMsg = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE, id, 0, 0);
+ session.reply(key, new DataSequenceLoadMessage(respLoadMsg));
+ }
+ // 瑙f瀽CMD_GETDSDIFF_REQUEST 璇锋眰鐨勬儏鍐
+ else if (object instanceof DSDiffRequestResult) {
+
+ DSDiffRequestResult requestResult = (DSDiffRequestResult)object;
+ String id = requestResult.getId();
+ long fromHeight = requestResult.getFromHeight();
+ long toHeight = requestResult.getToHeight();
+ //姣忎釜楂樺害鐨勬暟鎹簭鍒楀樊寮傚厓绱犺繘琛屼竴娆″搷搴旂殑鎯呭喌
+ for (long i = fromHeight; i < toHeight + 1; i++) {
+ byte[] respLoadMsg = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE, id, i, i);
+ session.reply(key, new DataSequenceLoadMessage(respLoadMsg));
+ }
+ //鎵鏈夊樊寮傝繘琛屼竴娆″搷搴旂殑鎯呭喌
+ }
+ else {
+ throw new IllegalArgumentException("Receive data exception, unknown message type!");
+ }
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * 鍝嶅簲绫诲瀷璁剧疆
+ * 鍒嗘墜鍔ㄥ搷搴旓紝鑷姩鍝嶅簲涓ょ绫诲瀷
+ */
+ @Override
+ public REPLY replyType() {
+ return REPLY.MANUAL;
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSMsgResolverFactory.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSMsgResolverFactory.java
new file mode 100644
index 00000000..c0dfae8d
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSMsgResolverFactory.java
@@ -0,0 +1,34 @@
+package com.jd.blockchain.statetransfer.message;
+
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+
+/**
+ * 鏁版嵁搴忓垪娑堟伅瑙f瀽鍣ㄥ伐鍘
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ *
+ */
+public class DSMsgResolverFactory {
+
+ /**
+ * 鑾峰緱鏁版嵁搴忓垪娑堟伅缂栫爜鍣ㄥ疄渚
+ * @param dsWriter 宸紓璇锋眰鑰呮墽琛屾暟鎹簭鍒楁洿鏂扮殑鎵ц鍣
+ * @param dsReader 宸紓鍝嶅簲鑰呮墽琛屾暟鎹簭鍒楄鍙栫殑鎵ц鍣
+ * @return 娑堟伅缂栫爜鍣ㄥ疄渚
+ */
+ public static DataSequenceMsgEncoder getEncoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) {
+ return new DataSequenceMsgEncoder(dsWriter, dsReader);
+ }
+
+ /**
+ * 鑾峰緱鏁版嵁搴忓垪娑堟伅瑙g爜鍣ㄥ疄渚
+ * @param dsWriter 宸紓璇锋眰鑰呮墽琛屾暟鎹簭鍒楁洿鏂扮殑鎵ц鍣
+ * @param dsReader 宸紓鍝嶅簲鑰呮墽琛屾暟鎹簭鍒楄鍙栫殑鎵ц鍣
+ * @return 娑堟伅瑙g爜鍣ㄥ疄渚
+ */
+ public static DataSequenceMsgDecoder getDecoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) {
+ return new DataSequenceMsgDecoder(dsWriter, dsReader);
+ }
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceLoadMessage.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceLoadMessage.java
new file mode 100644
index 00000000..a4131e61
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceLoadMessage.java
@@ -0,0 +1,28 @@
+package com.jd.blockchain.statetransfer.message;
+
+import com.jd.blockchain.stp.communication.message.LoadMessage;
+
+/**
+ * 鏁版嵁搴忓垪澶嶅埗鐨勮礋杞芥秷鎭
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ *
+ */
+public class DataSequenceLoadMessage implements LoadMessage {
+
+ byte[] bytes;
+
+ public DataSequenceLoadMessage(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public void setBytes(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return bytes;
+ }
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgDecoder.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgDecoder.java
new file mode 100644
index 00000000..6bfa4c97
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgDecoder.java
@@ -0,0 +1,107 @@
+package com.jd.blockchain.statetransfer.message;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+import com.jd.blockchain.statetransfer.process.DSTransferProcess;
+import com.jd.blockchain.statetransfer.result.DSDiffRequestResult;
+import com.jd.blockchain.utils.io.BytesUtils;
+import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils;
+
+/**
+ * 鏁版嵁搴忓垪娑堟伅瑙g爜鍣
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DataSequenceMsgDecoder {
+
+ private int heightSize = 8;
+ private int msgTypeSize = 1;
+
+ private long respHeight;
+ private long fromHeight;
+ private long toHeight;
+ private int idSize;
+ private byte[] idBytes;
+ private String id;
+ private int diffElemSize;
+ private byte[] diffElem;
+ DataSequenceElement dsElement;
+
+ private DataSequenceWriter dsWriter;
+ private DataSequenceReader dsReader;
+
+ public DataSequenceMsgDecoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) {
+ this.dsWriter = dsWriter;
+ this.dsReader = dsReader;
+ }
+
+
+ /**
+ * 瀵圭紪杩囩爜鐨勫瓧鑺傛暟缁勮В鐮侊紝杩樺師鎴愬璞″疄渚
+ * @param loadMessage 瀛楄妭搴忓垪
+ * @return 瑙g爜鍚庣殑瀵硅薄
+ */
+ public Object decode(byte[] loadMessage) {
+
+ try {
+ if (loadMessage.length <= 5) {
+ System.out.println("LoadMessage size is less than 5!");
+ throw new IllegalArgumentException();
+ }
+
+ int dataLength = BytesUtils.toInt(loadMessage, 0, 4);
+ byte msgCode = loadMessage[4];
+
+ // send by diff provider, diff requester decode
+ if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE.CODE) {
+ respHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize);
+ idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize + heightSize, 4);
+ idBytes = new byte[idSize];
+ System.arraycopy(loadMessage, 4 + msgTypeSize + heightSize + 4, idBytes, 0, idSize);
+ id = new String(idBytes);
+ return new DataSequenceInfo(id, respHeight);
+ }
+ // send by diff provider, diff requester decode
+ else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE.CODE) {
+ diffElemSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize, 4);
+ diffElem = new byte[diffElemSize];
+ System.arraycopy(loadMessage, 4 + msgTypeSize + 4, diffElem, 0, diffElemSize);
+ dsElement = BinarySerializeUtils.deserialize(diffElem);
+ return dsElement;
+ }
+ // send by diff requester, diff provider decode
+ else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST.CODE) {
+ idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize, 4);
+ idBytes = new byte[idSize];
+ System.arraycopy(loadMessage, 4 + msgTypeSize + 4, idBytes, 0, idSize);
+ id = new String(idBytes);
+ return id;
+ }
+ // send by diff requester, diff provider decode
+ else if (msgCode == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST.CODE) {
+ fromHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize);
+ toHeight = BytesUtils.toLong(loadMessage, 4 + msgTypeSize + heightSize);
+ idSize = BytesUtils.toInt(loadMessage, 4 + msgTypeSize + heightSize + heightSize, 4);
+ idBytes = new byte[idSize];
+ System.arraycopy(loadMessage, 4 + msgTypeSize + heightSize + heightSize + 4, idBytes, 0, idSize);
+ id = new String(idBytes);
+ return new DSDiffRequestResult(id, fromHeight, toHeight);
+ }
+ else {
+ System.out.println("Unknown message type!");
+ throw new IllegalArgumentException();
+ }
+
+ } catch (Exception e) {
+ System.out.println("Error to decode message: " + e.getMessage() + "!");
+ e.printStackTrace();
+
+ }
+
+ return null;
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgEncoder.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgEncoder.java
new file mode 100644
index 00000000..71b3ef4c
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgEncoder.java
@@ -0,0 +1,133 @@
+package com.jd.blockchain.statetransfer.message;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+import com.jd.blockchain.statetransfer.process.DSTransferProcess;
+import com.jd.blockchain.utils.io.BytesUtils;
+import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils;
+
+/**
+ * 鏁版嵁搴忓垪娑堟伅缂栫爜鍣
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DataSequenceMsgEncoder {
+
+ private int heightSize = 8;
+ private int msgTypeSize = 1;
+
+ private DataSequenceWriter dsWriter;
+ private DataSequenceReader dsReader;
+
+ public DataSequenceMsgEncoder(DataSequenceWriter dsWriter, DataSequenceReader dsReader) {
+ this.dsWriter = dsWriter;
+ this.dsReader = dsReader;
+ }
+
+ /**
+ * 鐩墠鏆傛椂鑰冭檻fromHeight涓巘oHeight鐩稿悓鐨勬儏鍐碉紝鍗虫瘡娆″彧瀵逛竴涓珮搴︾殑宸紓鍐呭杩涜缂栫爜骞跺搷搴
+ * 鎶婃秷鎭紪鐮佹垚瀛楄妭鏁扮粍锛屽啀浜ょ粰閫氫俊灞備紶杈
+ * @param msgType 鏁版嵁搴忓垪鐘舵佸鍒舵秷鎭被鍨
+ * @param id 鏁版嵁搴忓垪鍞竴鏍囪瘑绗
+ * @param fromHeight 宸紓鍏冪礌璧峰楂樺害
+ * @param toHeight 宸紓鍏冪礌缁撴潫楂樺害
+ */
+ public byte[] encode(DSTransferProcess.DataSequenceMsgType msgType, String id, long fromHeight, long toHeight) {
+
+ try {
+
+ int dataLength;
+ int idSize = id.getBytes().length;
+ byte[] loadMessage = null;
+
+ // different encoding methods for different message types
+ // send by diff requester, diff requester encode
+ if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST) {
+
+ // CMD_DSINFO_REQUEST Message parts : 4 bytes total message size, 1 byte message type coe,
+ // 4 bytes id length, id content size bytes
+
+ dataLength = 4 + msgTypeSize + 4 + idSize;
+
+ loadMessage = new byte[dataLength];
+
+ System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4);
+ loadMessage[4] = msgType.CODE;
+ System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize, 4);
+ System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + 4, idSize);
+ }
+ // send by diff requester, diff requester encode
+ else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST) {
+
+ // CMD_GETDSDIFF_REQUEST Message parts : 4 bytes total message size, 1 byte message type coe, 8 bytes from height,
+ // 8 bytes to height, 4 bytes id length, id content size bytes
+
+ dataLength = 4 + msgTypeSize + heightSize + heightSize + 4 + idSize;
+
+ loadMessage = new byte[dataLength];
+
+ System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4);
+ loadMessage[4] = msgType.CODE;
+ System.arraycopy(BytesUtils.toBytes(fromHeight), 0, loadMessage, 4 + msgTypeSize, heightSize);
+ System.arraycopy(BytesUtils.toBytes(toHeight), 0, loadMessage, 4 + msgTypeSize + heightSize, heightSize);
+ System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize + heightSize + heightSize, 4);
+ System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + heightSize + heightSize + 4, idSize);
+ }
+ // send by diff provider, diff provider encode
+ else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_RESPONSE) {
+
+ // CMD_DSINFO_RESPONSE Message parts : 4 bytes total message size, 1 byte message type coe, 8 bytes data sequence local height,
+ // 4 bytes id length, id content size bytes
+
+ dataLength = 4 + msgTypeSize + heightSize + 4 + idSize;
+
+ loadMessage = new byte[dataLength];
+
+ System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4);
+ loadMessage[4] = msgType.CODE;
+ System.arraycopy(BytesUtils.toBytes(dsReader.getDSInfo(id).getHeight()), 0, loadMessage, 4 + msgTypeSize, heightSize);
+
+ System.arraycopy(BytesUtils.toBytes(idSize), 0, loadMessage, 4 + msgTypeSize + heightSize, 4);
+ System.arraycopy(id.getBytes(), 0, loadMessage, 4 + msgTypeSize + heightSize + 4, idSize);
+
+ }
+ // send by diff provider, diff provider encode
+ else if (msgType == DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_RESPONSE) {
+ if (fromHeight != toHeight) {
+ throw new IllegalArgumentException("Height parameter error!");
+ }
+
+ // CMD_DSINFO_RESPONSE Message parts : 4 bytes total message size, 1 byte message type coe,
+ // 4 bytes diffElem size, diff content size;
+
+ // 鍥炶皟reader,鑾峰緱杩欎釜楂樺害涓婄殑鎵鏈夊樊寮傜殑鏁版嵁搴忓垪鍐呭锛屽苟缁勭粐鎴怐ataSequenceElement缁撴瀯
+ DataSequenceElement element = dsReader.getDSDiffContent(id, fromHeight);
+
+ byte[] diffElem = BinarySerializeUtils.serialize(element);
+
+ dataLength = 4 + msgTypeSize + 4 + diffElem.length;
+ loadMessage = new byte[dataLength];
+
+ System.arraycopy(BytesUtils.toBytes(dataLength), 0, loadMessage, 0, 4); //total size
+ loadMessage[4] = msgType.CODE; //msgType size
+ System.arraycopy(BytesUtils.toBytes(diffElem.length), 0, loadMessage, 4 + msgTypeSize, 4); // diffElem size
+ System.arraycopy(diffElem, 0, loadMessage, 4 + msgTypeSize + 4, diffElem.length); // diffElem bytes
+ }
+ else {
+ System.out.println("Unknown message type!");
+ throw new IllegalArgumentException();
+ }
+
+ return loadMessage;
+
+ } catch (Exception e) {
+ System.out.println("Error to encode message type : " + msgType + "!");
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSProcessManager.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSProcessManager.java
new file mode 100644
index 00000000..97b14602
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSProcessManager.java
@@ -0,0 +1,186 @@
+package com.jd.blockchain.statetransfer.process;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+import com.jd.blockchain.statetransfer.comparator.DataSequenceComparator;
+import com.jd.blockchain.statetransfer.message.DSDefaultMessageExecutor;
+import com.jd.blockchain.statetransfer.result.DSInfoResponseResult;
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.callback.CallBackBarrier;
+import com.jd.blockchain.stp.communication.callback.CallBackDataListener;
+import com.jd.blockchain.stp.communication.manager.RemoteSessionManager;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+
+import java.net.InetSocketAddress;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * 鏁版嵁搴忓垪鐘舵佸鍒惰繃绋嬬鐞嗗櫒
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ *
+ */
+public class DSProcessManager {
+
+ private static Map dSProcessMap = new ConcurrentHashMap<>();
+ private RemoteSession[] remoteSessions;
+ private long dsInfoResponseTimeout = 20000;
+ private ExecutorService writeExecutors = Executors.newFixedThreadPool(5);
+ private int returnCode = 0;
+
+ /**
+ * 鍚姩涓涓寚瀹氭暟鎹簭鍒楃殑鐘舵佸鍒惰繃绋
+ * @param dsInfo 鏁版嵁搴忓垪褰撳墠鐘舵佷俊鎭
+ * @param listener 鏈湴鐩戝惉鑰
+ * @param targets 鐩爣缁撶偣
+ * @param dsWriter 宸紓璇锋眰鑰呮墽琛屾暟鎹簭鍒楁洿鏂扮殑鎵ц鍣
+ * @param dsReader 宸紓鍝嶅簲鑰呮墽琛屾暟鎹簭鍒楄鍙栫殑鎵ц鍣
+ * @return returnCode 鎵ц缁撴灉鐮
+ */
+ public int startDSProcess(DataSequenceInfo dsInfo, InetSocketAddress listener, InetSocketAddress[] targets, DataSequenceWriter dsWriter, DataSequenceReader dsReader) {
+
+ // create remote sessions manager锛 add listener
+ LocalNode listenNode = new LocalNode(listener.getHostName(), listener.getPort(), new DSDefaultMessageExecutor(dsReader, dsWriter));
+
+ RemoteSessionManager remoteSessionManager = new RemoteSessionManager(listenNode);
+
+ // data sequence transfer process life cycle start
+ DSTransferProcess dsTransferProcess = new DSTransferProcess(dsInfo, targets);
+ dsTransferProcess.setDSReader(dsReader);
+ dsTransferProcess.setDSWriter(dsWriter);
+ dsTransferProcess.setRemoteSessionManager(remoteSessionManager);
+
+ dSProcessMap.put(dsInfo.getId(), dsTransferProcess);
+
+ try {
+
+ //wait all listener nodes start
+ Thread.sleep(2000);
+
+ // start network connections with targets
+ dsTransferProcess.start();
+
+ //get all target sessions
+ remoteSessions = dsTransferProcess.getSessions();
+
+ // async message send process
+ CallBackBarrier callBackBarrier = CallBackBarrier.newCallBackBarrier(remoteSessions.length, dsInfoResponseTimeout);
+
+ // response message manage map
+ LinkedList dsInfoResponses = new LinkedList<>();
+
+ System.out.println("Async send CMD_DSINFO_REQUEST msg to targets will start!");
+ // step1: send get dsInfo request, then hold
+ for (RemoteSession remoteSession : remoteSessions) {
+ CallBackDataListener dsInfoResponse = dsTransferProcess.send(DSTransferProcess.DataSequenceMsgType.CMD_DSINFO_REQUEST, remoteSession, 0, 0, callBackBarrier);
+ dsInfoResponses.addLast(dsInfoResponse);
+ }
+
+ System.out.println("Wait CMD_DSINFO_RESPONSE msg from targets!");
+ // step2: collect get dsInfo response
+ LinkedList receiveResponses = new LinkedList<>();
+ if (callBackBarrier.tryCall()) {
+ Iterator iterator = dsInfoResponses.iterator();
+ while (iterator.hasNext()) {
+ CallBackDataListener receiveResponse = iterator.next();
+ if (receiveResponse.isDone()) {
+ receiveResponses.addLast(receiveResponse);
+ }
+ }
+ }
+
+ System.out.printf("%s:%d Compute diff info!\r\n", listener.getHostName(), listener.getPort());
+ // step3: process received responses
+ DSInfoResponseResult diffResult = dsTransferProcess.computeDiffInfo(receiveResponses);
+
+ System.out.printf("%s:%d Diff info result height = %x!\r\n", listener.getHostName(), listener.getPort(), diffResult.getMaxHeight());
+
+ // height diff
+ long diff = dsInfo.getHeight() - diffResult.getMaxHeight();
+
+ if (diff == 0 || diff > 0) {
+ System.out.printf("%s:%d No duplication is required!\r\n", listener.getHostName(), listener.getPort());
+ // no duplication is required锛 life cycle ends
+// dsTransferProcess.close();
+ dSProcessMap.remove(dsInfo.getId());
+ return returnCode;
+
+ }
+ else {
+ System.out.printf("%s:%d Duplication is required!\r\n", listener.getHostName(), listener.getPort());
+ // step4: async send get data sequence diff request
+ // single step get diff
+ // async message send process
+ CallBackBarrier callBackBarrierDiff = CallBackBarrier.newCallBackBarrier((int)(diffResult.getMaxHeight() - dsInfo.getHeight()), dsInfoResponseTimeout);
+ LinkedList dsDiffResponses = new LinkedList<>();
+
+ RemoteSession responseSession = findResponseSession(diffResult.getMaxHeightRemoteNode(), remoteSessions);
+ System.out.println("Async send CMD_GETDSDIFF_REQUEST msg to targets will start!");
+
+ // step5: collect get data sequence diff response
+ for (long height = dsInfo.getHeight() + 1; height < diffResult.getMaxHeight() + 1; height++) {
+ CallBackDataListener dsDiffResponse = dsTransferProcess.send(DSTransferProcess.DataSequenceMsgType.CMD_GETDSDIFF_REQUEST, responseSession, height, height, callBackBarrierDiff);
+ dsDiffResponses.addLast(dsDiffResponse);
+ }
+ // 涓婅堪鍙戦佷笉鍚堢悊锛岃冭檻涓娆℃у彂閫佽姹
+ System.out.println("Wait CMD_GETDSDIFF_RESPONSE msg from targets!");
+ LinkedList receiveDiffResponses = new LinkedList<>();
+ if (callBackBarrierDiff.tryCall()) {
+ for (int i = 0; i < dsDiffResponses.size(); i++) {
+ CallBackDataListener asyncFutureDiff = dsDiffResponses.get(i);
+ if (asyncFutureDiff.isDone()) {
+ receiveDiffResponses.addLast(asyncFutureDiff.getCallBackData());
+ }
+ }
+ }
+
+ System.out.printf("%s:%d ReceiveDiffResponses size = %d !\r\n", listener.getHostName(), listener.getPort(), receiveDiffResponses.size());
+ // step6: process data sequence diff response, update local data sequence state
+ System.out.println("Compute diff elements!");
+ ArrayList dataSequenceElements = dsTransferProcess.computeDiffElement(receiveDiffResponses.toArray(new byte[receiveDiffResponses.size()][]));
+ System.out.println("Update local data sequence!");
+ Collections.sort(dataSequenceElements, new DataSequenceComparator());
+ returnCode = dsWriter.updateDSInfo(dsInfo, dataSequenceElements.toArray(new DataSequenceElement[dataSequenceElements.size()]));
+
+ // data sequence transfer complete, close all sessions, end process life cycle
+ System.out.println("Close all sessions");
+// dsTransferProcess.close();
+ dSProcessMap.remove(dsInfo.getId());
+ }
+
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return returnCode;
+ }
+
+ /**
+ * 鏍规嵁杩滅缁撶偣鎵句笌杩滅缁撶偣寤虹珛鐨勪細璇
+ * @param remoteNode 杩滅缁撶偣
+ * @param remoteSessions 鏈湴缁存姢鐨勮繙绔粨鐐逛細璇濊〃
+ * @return 涓庤繙绔粨鐐瑰搴旂殑浼氳瘽
+ */
+ RemoteSession findResponseSession(RemoteNode remoteNode, RemoteSession[] remoteSessions) {
+ for (RemoteSession remoteSession : remoteSessions) {
+ if (remoteSession.remoteNode().equals(remoteNode)) {
+ return remoteSession;
+ }
+ }
+ return null;
+ }
+ /**
+ *
+ *
+ */
+// void setDSReader(DataSequenceReader reader) {
+//
+// }
+
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSTransferProcess.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSTransferProcess.java
new file mode 100644
index 00000000..45fc89fb
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSTransferProcess.java
@@ -0,0 +1,216 @@
+package com.jd.blockchain.statetransfer.process;
+
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+import com.jd.blockchain.statetransfer.callback.DataSequenceReader;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriter;
+import com.jd.blockchain.statetransfer.message.DSMsgResolverFactory;
+import com.jd.blockchain.statetransfer.message.DataSequenceLoadMessage;
+import com.jd.blockchain.statetransfer.result.DSInfoResponseResult;
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.callback.CallBackBarrier;
+import com.jd.blockchain.stp.communication.callback.CallBackDataListener;
+import com.jd.blockchain.stp.communication.manager.RemoteSessionManager;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import com.jd.blockchain.utils.IllegalDataException;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * 鏁版嵁搴忓垪鐘舵佸鍒惰繃绋
+ * @author zhangshuang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+public class DSTransferProcess {
+
+ private InetSocketAddress[] targets;
+ private DataSequenceWriter dsWriter;
+ private DataSequenceReader dsReader;
+ private DataSequenceInfo dsInfo;
+ private RemoteSessionManager remoteSessionManager;
+ private RemoteSession[] remoteSessions;
+ private String id;
+
+ /**
+ * @param dsInfo 鏁版嵁搴忓垪褰撳墠鐘舵佷俊鎭
+ * @param targets 鐩爣缁撶偣
+ */
+ public DSTransferProcess(DataSequenceInfo dsInfo, InetSocketAddress[] targets) {
+ this.dsInfo = dsInfo;
+ this.targets = targets;
+ this.id = dsInfo.getId();
+ }
+
+ /**
+ * @param dsWriter 宸紓璇锋眰鑰呮墽琛屾暟鎹簭鍒楁洿鏂扮殑鎵ц鍣
+ * @return void
+ */
+ public void setDSWriter(DataSequenceWriter dsWriter) {
+ this.dsWriter = dsWriter;
+ }
+
+ /**
+ * @param dsReader 宸紓鍝嶅簲鑰呮墽琛屾暟鎹簭鍒楄鍙栫殑鎵ц鍣
+ * @return void
+ */
+ public void setDSReader(DataSequenceReader dsReader) {
+ this.dsReader = dsReader;
+ }
+
+ /**
+ * @param remoteSessionManager 杩滅浼氳瘽绠$悊鍣
+ * @return void
+ */
+ public void setRemoteSessionManager(RemoteSessionManager remoteSessionManager) {
+ this.remoteSessionManager = remoteSessionManager;
+ }
+
+
+ /**
+ *
+ * @return 鏁版嵁搴忓垪鏍囪瘑绗
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * @param msgType 鏁版嵁搴忓垪宸紓璇锋眰娑堟伅绫诲瀷
+ * @param remoteSession 鐩爣缁撶偣瀵瑰簲鐨勪細璇
+ * @param fromHeight 宸紓璧峰楂樺害
+ * @param toHeight 宸紓缁撴潫楂樺害
+ * @param callBackBarrier 寮傛鍥炶皟
+ * @return 寮傛鍥炶皟
+ */
+ CallBackDataListener send(DataSequenceMsgType msgType, RemoteSession remoteSession, long fromHeight, long toHeight, CallBackBarrier callBackBarrier) {
+
+ byte[] loadMessage = DSMsgResolverFactory.getEncoder(dsWriter, dsReader).encode(msgType, id, fromHeight, toHeight);
+
+ return remoteSession.asyncRequest(new DataSequenceLoadMessage(loadMessage), callBackBarrier);
+ }
+
+ /**
+ * 璁$畻鏁版嵁搴忓垪宸紓鍏冪礌鏁扮粍
+ * @param diffArray 宸紓鐨勫瓧鑺傛暟缁
+ * @return 瀵瑰樊寮傚瓧鑺傛暟缁勭殑瑙g爜缁撴灉
+ */
+ public ArrayList computeDiffElement(byte[][] diffArray) {
+
+ ArrayList dataSequenceElements = new ArrayList<>();
+
+ for (int i = 0 ; i < diffArray.length; i++) {
+ Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(diffArray[i]);
+ if (object instanceof DataSequenceElement) {
+ dataSequenceElements.add((DataSequenceElement) object);
+ }
+ else {
+ throw new IllegalDataException("Unknown instance object!");
+ }
+ }
+
+ return dataSequenceElements;
+ }
+
+ /**
+ * 鏍规嵁宸紓鎻愪緵鑰呭搷搴旂殑鏁版嵁搴忓垪鐘舵佷俊鎭壘鍒版嫢鏈夋渶澶ф暟鎹簭鍒楅珮搴︾殑杩滅缁撶偣
+ * @param receiveResponses 鏁版嵁搴忓垪宸紓璇锋眰鑰呮敹鍒扮殑杩滅缁撶偣鐘舵佺殑鍝嶅簲淇℃伅
+ * @return 寰楀埌杩滅鏁版嵁搴忓垪鐨勬渶澶ч珮搴︿互鍙婃嫢鏈夎呯粨鐐
+ */
+ public DSInfoResponseResult computeDiffInfo(LinkedList receiveResponses) {
+ long maxHeight = 0;
+ RemoteNode maxHeightRemoteNode = null;
+
+ System.out.println("ComputeDiffInfo receiveResponses size = "+ receiveResponses.size());
+
+ try {
+ for (CallBackDataListener receiveResponse : receiveResponses) {
+ Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(receiveResponse.getCallBackData());
+ if (object instanceof DataSequenceInfo) {
+ DataSequenceInfo dsInfo = (DataSequenceInfo) object;
+ long height = dsInfo.getHeight();
+ // sava max height and its remote node
+ if (maxHeight < height) {
+ maxHeight = height;
+ maxHeightRemoteNode = receiveResponse.remoteNode();
+ }
+ }
+ else {
+ throw new IllegalDataException("Unknown instance object!");
+ }
+
+ }
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ }
+
+ return new DSInfoResponseResult(maxHeight, maxHeightRemoteNode);
+ }
+
+ /**
+ * 鑾峰彇鏈鍒惰繃绋嬬淮鎶ょ殑杩滅浼氳瘽琛
+ * @param
+ * @return 杩滅浼氳瘽琛ㄦ暟缁
+ */
+ public RemoteSession[] getSessions() {
+ return remoteSessions;
+ }
+
+ /**
+ * 鍏抽棴鏈鍒惰繃绋嬬淮鎶ょ殑鎵鏈夎繙绔細璇
+ * @return void
+ */
+ public void close() {
+ for (RemoteSession session : remoteSessions) {
+ session.closeAll();
+ }
+ }
+
+ /**
+ * 寤虹珛涓庤繙绔洰鏍囩粨鐐圭殑杩炴帴锛屼骇鐢熸湰鍦扮淮鎶ょ殑杩滅浼氳瘽琛
+ * @return void
+ */
+ public void start() {
+
+ RemoteNode[] remoteNodes = new RemoteNode[targets.length];
+
+ for (int i = 0; i < remoteNodes.length; i++) {
+ remoteNodes[i] = new RemoteNode(targets[i].getHostName(), targets[i].getPort());
+ }
+
+ remoteSessions = remoteSessionManager.newSessions(remoteNodes);
+ }
+
+
+ /**
+ * 鏁版嵁搴忓垪鐘舵佷紶杈撲娇鐢ㄧ殑娑堟伅绫诲瀷
+ *
+ */
+ public enum DataSequenceMsgType {
+ CMD_DSINFO_REQUEST((byte) 0x1),
+ CMD_DSINFO_RESPONSE((byte) 0x2),
+ CMD_GETDSDIFF_REQUEST((byte) 0x3),
+ CMD_GETDSDIFF_RESPONSE((byte) 0x4),
+ ;
+ public final byte CODE;
+
+ private DataSequenceMsgType(byte code) {
+ this.CODE = code;
+ }
+
+ public static DataSequenceMsgType valueOf(byte code) {
+ for (DataSequenceMsgType msgType : DataSequenceMsgType.values()) {
+ if (msgType.CODE == code) {
+ return msgType;
+ }
+ }
+ throw new IllegalArgumentException("Unsupported code[" + code + "] of msgType!");
+ }
+ }
+
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSDiffRequestResult.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSDiffRequestResult.java
new file mode 100644
index 00000000..af62bd6c
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSDiffRequestResult.java
@@ -0,0 +1,45 @@
+package com.jd.blockchain.statetransfer.result;
+
+/**
+ * 鏁版嵁搴忓垪宸紓鎻愪緵鑰呰В鐮佽姹傝"CMD_GETDSDIFF_REQUEST"娑堟伅鏃跺緱鍒扮殑缁撴灉
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DSDiffRequestResult {
+
+ String id;
+ long fromHeight;
+ long toHeight;
+
+ public DSDiffRequestResult(String id ,long fromHeight, long toHeight) {
+ this.id = id;
+ this.fromHeight = fromHeight;
+ this.toHeight = toHeight;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public long getFromHeight() {
+ return fromHeight;
+ }
+
+ public long getToHeight() {
+ return toHeight;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setFromHeight(long fromHeight) {
+ this.fromHeight = fromHeight;
+ }
+
+ public void setToHeight(long toHeight) {
+ this.toHeight = toHeight;
+ }
+
+}
diff --git a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSInfoResponseResult.java b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSInfoResponseResult.java
new file mode 100644
index 00000000..7f6d48cc
--- /dev/null
+++ b/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSInfoResponseResult.java
@@ -0,0 +1,37 @@
+package com.jd.blockchain.statetransfer.result;
+
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+
+/**
+ * 鏁版嵁搴忓垪宸紓璇锋眰鑰呰В鐮佹彁渚涜"CMD_DSINFO_RESPONSE"娑堟伅鏃跺緱鍒扮殑缁撴灉
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class DSInfoResponseResult {
+
+ long maxHeight;
+ RemoteNode maxHeightRemoteNode;
+
+ public DSInfoResponseResult(long maxHeight, RemoteNode maxHeightRemoteNode) {
+ this.maxHeight = maxHeight;
+ this.maxHeightRemoteNode = maxHeightRemoteNode;
+ }
+
+ public long getMaxHeight() {
+ return maxHeight;
+ }
+
+ public RemoteNode getMaxHeightRemoteNode() {
+ return maxHeightRemoteNode;
+ }
+
+ public void setMaxHeight(long maxHeight) {
+ this.maxHeight = maxHeight;
+ }
+
+ public void setMaxHeightRemoteNode(RemoteNode maxHeightRemoteNode) {
+ this.maxHeightRemoteNode = maxHeightRemoteNode;
+ }
+
+}
diff --git a/source/state-transfer/src/test/java/test/com/jd/blockchain/statetransfer/StateTransferLayerTest.java b/source/state-transfer/src/test/java/test/com/jd/blockchain/statetransfer/StateTransferLayerTest.java
new file mode 100644
index 00000000..5741262e
--- /dev/null
+++ b/source/state-transfer/src/test/java/test/com/jd/blockchain/statetransfer/StateTransferLayerTest.java
@@ -0,0 +1,155 @@
+package test.com.jd.blockchain.statetransfer;
+
+import com.jd.blockchain.statetransfer.DataSequence;
+import com.jd.blockchain.statetransfer.DataSequenceElement;
+import com.jd.blockchain.statetransfer.DataSequenceInfo;
+import com.jd.blockchain.statetransfer.callback.DataSequenceReaderImpl;
+import com.jd.blockchain.statetransfer.callback.DataSequenceWriterImpl;
+import com.jd.blockchain.statetransfer.process.DSProcessManager;
+import com.jd.blockchain.utils.codec.Base58Utils;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.net.InetSocketAddress;
+import java.util.LinkedList;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author zhangshuang
+ * @create 2019/4/18
+ * @since 1.0.0
+ */
+public class StateTransferLayerTest {
+
+ private final int[] listenPorts = new int[]{9000, 9010, 9020, 9030};
+
+ private String localIp = "127.0.0.1";
+
+ private int DataSequenceNum = 1;
+
+ private int nodesNum = 4;
+
+ private byte[] idBytes = new byte[20];
+
+ private Random rand = new Random();
+
+ private String[] dataSequenceIds = new String[DataSequenceNum];
+
+ private InetSocketAddress[] remoteNodeIps = new InetSocketAddress[nodesNum];
+
+ private final ExecutorService threadPool = Executors.newFixedThreadPool(8);
+
+ private static LinkedList dataSequencesPerNode = new LinkedList<>();
+
+ // 鍋囧畾姣忎釜鏁版嵁搴忓垪鍏冪礌閲屾湁鍥涙潯璁板綍鏁版嵁
+ private byte[][] dsElementDatas = new byte[4][];
+
+
+ @Before
+ public void init() {
+
+ // 浜х敓涓や釜鍞竴鐨勬暟鎹簭鍒桰d鏍囪瘑
+ for (int i = 0; i < DataSequenceNum; i++) {
+
+ dataSequenceIds[i] = new String();
+ rand.nextBytes(idBytes);
+ dataSequenceIds[i] = Base58Utils.encode(idBytes);
+ }
+
+ // 鍑嗗濂芥墍鏈夌殑杩滅缁撶偣锛屽寘鎷洃鍚
+ for (int i = 0; i < nodesNum; i++) {
+ remoteNodeIps[i] = new InetSocketAddress(localIp, listenPorts[i]);
+ }
+
+ // 涓烘暟鎹簭鍒楃殑姣忎釜楂樺害鍑嗗濂藉唴瀹癸紝涓轰簡鏂逛究娴嬭瘯锛屾瘡涓珮搴︾殑鍐呭璁剧疆涓轰竴鑷
+ for (int i = 0; i < dsElementDatas.length; i++) {
+ rand.nextBytes(idBytes);
+ dsElementDatas[i] = idBytes;
+ }
+
+ // 涓虹粨鐐瑰噯澶囨暟鎹簭鍒
+ for (String id : dataSequenceIds) {
+ for (int i = 0; i < remoteNodeIps.length; i++) {
+ DataSequence dataSequence = new DataSequence(remoteNodeIps[i], id);
+
+ // 涓烘暟鎹簭鍒楃殑0锛1锛2楂樺害娣诲姞鍐呭
+ for (int j = 0; j < 3; j++) {
+ dataSequence.addElement(new DataSequenceElement(id, j, dsElementDatas));
+ }
+ dataSequencesPerNode.addLast(dataSequence);
+ }
+
+ // 鎶婂叾涓竴涓粨鐐圭殑鏁版嵁搴忓垪涓庡叾浠栫粨鐐瑰尯鍒紑鏉
+ for (int i = 0; i < dataSequencesPerNode.size(); i++) {
+ DataSequence dataSequence = dataSequencesPerNode.get(i);
+ if (dataSequence.getAddress().getPort() != listenPorts[0]) {
+ // 涓烘暟鎹簭鍒楃殑3,4楂樺害娣诲姞鍐呭
+ for (int j = 3; j < 5; j++) {
+ dataSequence.addElement(new DataSequenceElement(id, j, dsElementDatas));
+ }
+ }
+ }
+ }
+ }
+
+ InetSocketAddress[] getTargetNodesIp(InetSocketAddress listenIp, InetSocketAddress[] remoteNodeIps) {
+
+ // 鑾峰緱闄ょ洃鍚粨鐐逛箣澶栫殑鍏朵粬杩滅缁撶偣
+ InetSocketAddress[] targets = new InetSocketAddress[remoteNodeIps.length - 1];
+ int j = 0;
+
+ for (int i = 0; i < remoteNodeIps.length; i++) {
+ if ((remoteNodeIps[i].getHostName().equals(listenIp.getHostName())) && (remoteNodeIps[i].getPort() == listenIp.getPort())) {
+ continue;
+ }
+ targets[j++] = new InetSocketAddress(remoteNodeIps[i].getHostName(), remoteNodeIps[i].getPort());
+ }
+
+ return targets;
+
+ }
+
+
+ DataSequence findDataSequence(String id, InetSocketAddress listenNodeAddr) {
+ for (DataSequence dataSequence : dataSequencesPerNode) {
+ if ((dataSequence.getAddress().getPort() == listenNodeAddr.getPort() && (dataSequence.getAddress().getHostName().equals(listenNodeAddr.getHostName()))
+ && (dataSequence.getId().equals(id)))) {
+ return dataSequence;
+ }
+ }
+ return null;
+ }
+
+
+ @Test
+ public void test() {
+
+ CountDownLatch countDownLatch = new CountDownLatch(nodesNum);
+
+ for (String id : dataSequenceIds) {
+ for (int i = 0; i < nodesNum; i++) {
+ InetSocketAddress listenNode = remoteNodeIps[i];
+ threadPool.execute(() -> {
+ // 鍒涘缓鏁版嵁搴忓垪澶勭悊绠$悊鑰呭疄渚
+ DSProcessManager dsProcessManager = new DSProcessManager();
+ DataSequence currDataSequence = findDataSequence(id, listenNode);
+ DataSequenceInfo dsInfo = currDataSequence.getDSInfo();
+ InetSocketAddress[] targets = getTargetNodesIp(listenNode, remoteNodeIps);
+ dsProcessManager.startDSProcess(dsInfo, listenNode, targets, new DataSequenceWriterImpl(currDataSequence), new DataSequenceReaderImpl(currDataSequence));
+ countDownLatch.countDown();
+ });
+ }
+ }
+
+ // 绛夊緟鏁版嵁搴忓垪鏇存柊瀹屾垚
+ try {
+ Thread.sleep(60000);
+ countDownLatch.await();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/source/stp/pom.xml b/source/stp/pom.xml
new file mode 100644
index 00000000..fd7fc35e
--- /dev/null
+++ b/source/stp/pom.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ jdchain-root
+ com.jd.blockchain
+ 0.9.0-SNAPSHOT
+
+ 4.0.0
+
+ stp
+ pom
+
+ stp-communication
+
+
+
+ UTF-8
+
+
diff --git a/source/stp/stp-communication/pom.xml b/source/stp/stp-communication/pom.xml
new file mode 100644
index 00000000..96798377
--- /dev/null
+++ b/source/stp/stp-communication/pom.xml
@@ -0,0 +1,50 @@
+
+
+
+
+ stp
+ com.jd.blockchain
+ 0.9.0-SNAPSHOT
+
+ 4.0.0
+
+ stp-communication
+
+ stp-communication
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+ commons-codec
+ commons-codec
+
+
+
+ com.alibaba
+ fastjson
+
+
+
+ io.netty
+ netty-all
+ 4.1.29.Final
+
+
+
+ com.google.guava
+ guava
+
+
+
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/MessageExecutor.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/MessageExecutor.java
new file mode 100644
index 00000000..dba7e0d0
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/MessageExecutor.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.MessageExecutor
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍10:59
+ * Description:
+ */
+package com.jd.blockchain.stp.communication;
+
+/**
+ * 娑堟伅鎵ц鍣
+ * 璇ユ墽琛屽櫒鐢卞叾浠栧簲鐢ㄥ疄鐜
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ * @date 2019-04-18 15:29
+ */
+
+public interface MessageExecutor {
+
+ /**
+ * 鎺ユ敹鍒皉eceive娑堟伅濡備綍澶勭悊
+ *
+ * @param key
+ * 璇锋眰娑堟伅鐨凨ey锛岃皟鐢ㄨ呴渶瑕佸湪搴旂瓟鏃堕氳繃璇ey搴旂瓟杩滅
+ * @param data
+ * 璇锋眰娑堟伅鐨勫唴瀹
+ * @param session
+ * 杩滅Session锛屾弿杩拌娑堟伅鏄粠鍝彂閫佹潵鐨
+ * @return
+ * 搴旂瓟缁撴灉
+ */
+ byte[] receive(String key, byte[] data, RemoteSession session);
+
+ /**
+ * 搴旂瓟鏂瑰紡
+ *
+ * @return
+ * 鍙傝冿細{@link REPLY}
+ */
+ REPLY replyType();
+
+ // 搴旂瓟鏂瑰紡
+ enum REPLY {
+ // 鎵嬪姩搴旂瓟锛歊eceiver涓嶄細鑷姩鍙戦佸簲绛旇姹傦紝闇瑕佽皟鐢
+ // session.reply(String key, LoadMessage loadMessage) 鎴
+ // asyncReply(String key, LoadMessage loadMessage)
+ MANUAL,
+
+ // 鑷姩搴旂瓟锛歊eceiver浼氭牴鎹畆eceive鏂规硶鐨勫簲绛旂粨鏋滆嚜鍔ㄨ皟鐢ㄥ簲绛
+ // 浣跨敤鑰呬笉鑳介噸鏂拌皟鐢
+ AUTO,
+ ;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/RemoteSession.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/RemoteSession.java
new file mode 100644
index 00000000..0ce9fceb
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/RemoteSession.java
@@ -0,0 +1,206 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.RemoteSession
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍11:15
+ * Description:
+ */
+package com.jd.blockchain.stp.communication;
+
+import com.jd.blockchain.stp.communication.callback.CallBackBarrier;
+import com.jd.blockchain.stp.communication.callback.CallBackDataListener;
+import com.jd.blockchain.stp.communication.connection.Connection;
+import com.jd.blockchain.stp.communication.message.LoadMessage;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import org.apache.commons.codec.binary.Hex;
+
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * 杩滅Session
+ *
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+
+public class RemoteSession {
+
+ /**
+ * 鏈湴鑺傜偣ID
+ */
+ private String localId;
+
+ /**
+ * 杩滅鑺傜偣
+ */
+ private RemoteNode remoteNode;
+
+ /**
+ * 杩滅杩炴帴
+ */
+ private Connection connection;
+
+ /**
+ * 瀵瑰簲杩滅鑺傜偣娑堟伅鐨勫鐞嗗櫒
+ * 璇ュ鐞嗗櫒鑻ヤ负NULL锛屽垯浣跨敤褰撳墠鑺傜偣榛樿澶勭悊鍣
+ */
+ private MessageExecutor messageExecutor;
+
+ /**
+ * 鏋勯犲櫒
+ * @param localId
+ * 鏈湴鑺傜偣ID
+ * @param connection
+ * 瀵瑰簲杩炴帴
+ */
+ public RemoteSession(String localId, Connection connection) {
+ this(localId, connection, null);
+ }
+
+ /**
+ * 鏋勯犲櫒
+ * @param localId
+ * 鏈湴鑺傜偣ID
+ * @param connection
+ * 瀵瑰簲杩炴帴
+ * @param messageExecutor
+ * 瀵瑰簲杩滅娑堟伅澶勭悊鍣
+ */
+ public RemoteSession(String localId, Connection connection, MessageExecutor messageExecutor) {
+ this.localId = localId;
+ this.connection = connection;
+ this.messageExecutor = messageExecutor;
+ this.remoteNode = connection.remoteNode();
+ }
+
+ public void init() {
+ connection.initSession(this);
+ }
+
+ public void initExecutor(MessageExecutor messageExecutor) {
+ this.messageExecutor = messageExecutor;
+ }
+
+ /**
+ * 鍚屾璇锋眰
+ * 璇ヨ姹備細闃诲鍘熺嚎绋
+ *
+ * @param loadMessage
+ * 瑕佽姹傜殑璐熻浇娑堟伅
+ * @return
+ * 搴旂瓟锛岀洿鍒版湁娑堟伅搴旂瓟鎴栧嚭鐜板紓甯
+ * @throws Exception
+ */
+ public byte[] request(LoadMessage loadMessage) throws Exception {
+ return this.connection.request(this.localId, loadMessage, null).getCallBackData();
+ }
+
+ /**
+ * 鍚屾璇锋眰
+ * 璇ヨ姹備細闃诲鍘熺嚎绋
+ *
+ * @param loadMessage
+ * 瑕佽姹傜殑璐熻浇娑堟伅
+ * @param time
+ * 璇锋眰鐨勬渶闀跨瓑寰呮椂闂
+ * @param timeUnit
+ * 璇锋眰鐨勬渶闀跨瓑寰呭崟浣
+ * @return
+ * 搴旂瓟锛岀洿鍒版湁娑堟伅鎴栨椂闂存埅姝㈡垨鍑虹幇寮傚父
+ * @throws Exception
+ */
+ public byte[] request(LoadMessage loadMessage, long time, TimeUnit timeUnit) throws Exception {
+ return this.connection.request(this.localId, loadMessage, null).getCallBackData(time, timeUnit);
+ }
+
+ /**
+ * 寮傛璇锋眰
+ * 涓嶄細闃诲璋冪敤绾跨▼
+ *
+ * @param loadMessage
+ * 瑕佸彂閫佺殑璐熻浇娑堟伅
+ * @return
+ * 搴旂瓟锛岄渶瑕佽皟鐢ㄨ呬粠Listener涓幏鍙栫粨鏋
+ */
+ public CallBackDataListener asyncRequest(LoadMessage loadMessage) {
+ return asyncRequest(loadMessage, null);
+ }
+
+ /**
+ * 寮傛璇锋眰
+ * 涓嶄細闃诲璋冪敤绾跨▼
+ *
+ * @param loadMessage
+ * 瑕佽姹傜殑璐熻浇娑堟伅
+ * @param callBackBarrier
+ * 鍥炶皟鏍呮爮锛堢敤浜庡涓姹傛椂杩涜缁熶竴闃绘嫤锛
+ * @return
+ * 搴旂瓟锛岄渶瑕佽皟鐢ㄨ呬粠Listener涓幏鍙栫粨鏋
+ */
+ public CallBackDataListener asyncRequest(LoadMessage loadMessage, CallBackBarrier callBackBarrier) {
+ return this.connection.request(this.localId, loadMessage, callBackBarrier);
+ }
+
+ /**
+ * 搴旂瓟
+ *
+ * @param key
+ * 璇锋眰娑堟伅鐨凨ey
+ * @param loadMessage
+ * 闇瑕佸簲绛旂殑璐熻浇娑堟伅
+ */
+ public void reply(String key, LoadMessage loadMessage) {
+ this.connection.reply(this.localId, key, loadMessage);
+ }
+
+ public void closeAll() {
+ this.connection.closeAll();
+ }
+
+ public void closeReceiver() {
+ this.connection.closeReceiver();
+ }
+
+ public void closeSender() {
+ this.connection.closeSender();
+ }
+
+ /**
+ * 杩斿洖鏈湴鑺傜偣ID
+ *
+ * @return
+ */
+ public String localId() {
+ return localId;
+ }
+
+ /**
+ * 杩斿洖杩滅瀵瑰簲鐨凷essionID
+ *
+ * @return
+ */
+ public String remoteSessionId() {
+ return Hex.encodeHexString(remoteNode.toString().getBytes());
+ }
+
+ /**
+ * 杩斿洖杩滅瀵瑰簲鎵ц鍣
+ *
+ * @return
+ */
+ public MessageExecutor messageExecutor() {
+ return this.messageExecutor;
+ }
+
+ /**
+ * 杩斿洖瀵瑰簲杩滅鑺傜偣
+ *
+ * @return
+ */
+ public RemoteNode remoteNode() {
+ return remoteNode;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackBarrier.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackBarrier.java
new file mode 100644
index 00000000..41da6b66
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackBarrier.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.CallBackBarrier
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/12 涓婂崍10:22
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.callback;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 鍥炶皟鏍呮爮
+ * 鐢ㄤ簬瀵规壒閲忚姹傜殑搴旂瓟鍥炶皟澶勭悊
+ * @author shaozhuguang
+ * @create 2019/4/12
+ * @since 1.0.0
+ */
+
+public class CallBackBarrier {
+
+ private CountDownLatch countDownLatch;
+
+ /**
+ * 榛樿鏈澶у皾璇曡皟鐢ㄦ椂闂达紙鍗曚綅锛氭绉掞級
+ */
+ private long maxTryCallMillSeconds = 2000;
+
+
+ /**
+ * 闈欐佹瀯閫犲櫒
+ * @param barrierLength
+ * 璇锋眰鐨勮繙绔暟閲
+ * @return
+ */
+ public static final CallBackBarrier newCallBackBarrier(int barrierLength) {
+ return new CallBackBarrier(barrierLength);
+ }
+
+ /**
+ * 闈欐佹瀯閫犲櫒
+ * @param barrierLength
+ * 璇锋眰鐨勮繙绔暟閲
+ * @param maxTryCallMillSeconds
+ * 鏈澶у皾璇曠殑鏃堕棿锛屽崟浣嶏細姣
+ * @return
+ */
+ public static final CallBackBarrier newCallBackBarrier(int barrierLength, long maxTryCallMillSeconds) {
+ return new CallBackBarrier(barrierLength, maxTryCallMillSeconds);
+ }
+
+ private CallBackBarrier(int barrierLength) {
+ this.countDownLatch = new CountDownLatch(barrierLength);
+ }
+
+ private CallBackBarrier(int barrierLength, long maxTryCallMillSeconds) {
+ this.countDownLatch = new CountDownLatch(barrierLength);
+ this.maxTryCallMillSeconds = maxTryCallMillSeconds;
+ }
+
+ public void release() {
+ countDownLatch.countDown();
+ }
+
+ public boolean tryCall() throws InterruptedException {
+ return countDownLatch.await(maxTryCallMillSeconds, TimeUnit.MILLISECONDS);
+ }
+
+ public boolean tryCall(long timeout, TimeUnit unit) throws InterruptedException {
+ return countDownLatch.await(timeout, unit);
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackDataListener.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackDataListener.java
new file mode 100644
index 00000000..9de7aa32
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackDataListener.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.callback.CallBackDataListener
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/15 涓嬪崍4:40
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.callback;
+
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 鏁版嵁鍥炶皟鐩戝惉鍣
+ * @author shaozhuguang
+ * @create 2019/4/15
+ * @since 1.0.0
+ */
+
+public class CallBackDataListener {
+
+ /**
+ * Future
+ */
+ private CompletableFuture future = new CompletableFuture<>();
+
+ /**
+ * 杩滅鑺傜偣
+ */
+ private RemoteNode remoteNode;
+
+ private boolean isFill = false;
+
+ private Lock lock = new ReentrantLock();
+
+
+ /**
+ * 鏋勯犲櫒
+ * @param remoteNode
+ * 杩滅鑺傜偣淇℃伅
+ */
+ public CallBackDataListener(RemoteNode remoteNode) {
+ this.remoteNode = remoteNode;
+ }
+
+ /**
+ * 鑾峰彇杩斿洖鐨勬暟鎹
+ * 璋冪敤璇ユ柟娉曚細闃诲褰撳墠绾跨▼锛岀洿鍒版湁鏁版嵁杩斿洖鎴栧嚭鐜板紓甯
+ * @return
+ * 搴旂瓟缁撴灉
+ * @throws InterruptedException
+ * @throws ExecutionException
+ */
+ public byte[] getCallBackData() throws InterruptedException, ExecutionException {
+ return future.get();
+ }
+
+ /**
+ * 鎸囧畾鏃堕棿鍐呰幏鍙栬繑鍥炵殑鏁版嵁
+ * 璋冪敤璇ユ柟娉曚細闃诲褰撳墠绾跨▼锛岀洿鍒版椂闂村埌杈炬垨鏈夋暟鎹繑鍥炴垨鍑虹幇寮傚父
+ * @param time
+ * 瓒呮椂鏃堕棿
+ * @param timeUnit
+ * 瓒呮椂鍗曚綅
+ * @return
+ * 搴旂瓟缁撴灉锛岃嫢鎸囧畾鏃堕棿鍐呮病鏈夋暟鎹紝鍒欒繑鍥瀗ull
+ * @throws InterruptedException
+ * @throws ExecutionException
+ * @throws TimeoutException
+ */
+ public byte[] getCallBackData(long time, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
+ return future.get(time, timeUnit);
+ }
+
+ /**
+ * 璁剧疆杩斿洖鐨勬暟鎹
+ * @param data
+ */
+ public void setCallBackData(byte[] data) {
+ // 闃叉鏁版嵁澶氭璁剧疆
+ if (!isFill) {
+ try {
+ lock.lock();
+ // Double Check
+ if (!isFill) {
+ future.complete(data);
+ isFill = true;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
+
+ public RemoteNode remoteNode() {
+ return this.remoteNode;
+ }
+
+ /**
+ * 鍒ゆ柇鏄惁寮傛鎿嶄綔瀹屾垚
+ * @return
+ */
+ public boolean isDone() {
+ return future.isDone();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackLauncher.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackLauncher.java
new file mode 100644
index 00000000..e1f9473a
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/callback/CallBackLauncher.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.callback.CallBackLauncher
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/17 涓嬪崍6:27
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.callback;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * 鍚姩鍣ㄥ洖璋
+ * @author shaozhuguang
+ * @create 2019/4/17
+ * @since 1.0.0
+ * @date 2019-04-19 09:53
+ */
+
+public class CallBackLauncher {
+
+ /**
+ * 鏄惁鍚姩鎴愬姛
+ */
+ private boolean isBootSuccess = false;
+
+ /**
+ * 淇″彿閲
+ */
+ private Semaphore isBooted = new Semaphore(0, true);
+
+ /**
+ * 寮傚父
+ */
+ private Exception exception;
+
+ /**
+ * 鏍囪瘑褰撳墠鍚姩鎴愬姛
+ */
+ public void bootSuccess() {
+ isBootSuccess = true;
+ release();
+ }
+
+ /**
+ * 鏍囪瘑褰撳墠鍚姩澶辫触
+ * @param e
+ * 瀵艰嚧澶辫触鐨勫紓甯镐俊鎭
+ */
+ public void bootFail(Exception e) {
+ this.exception = e;
+ isBootSuccess = false;
+ release();
+ }
+
+ /**
+ * 绛夊緟鍚姩瀹屾垚
+ * 璋冪敤璇ユ柟娉曚細闃诲褰撳墠绾跨▼锛岀煡閬撳惎鍔ㄥ畬鎴愭垨鍙戠敓寮傚父
+ * @return
+ * 褰撳墠瀵硅薄
+ * @throws InterruptedException
+ */
+ public CallBackLauncher waitingBooted() throws InterruptedException {
+ this.isBooted.acquire();
+ return this;
+ }
+
+ public boolean isBootSuccess() {
+ return isBootSuccess;
+ }
+
+ public Exception exception() {
+ return exception;
+ }
+
+ private void release() {
+ this.isBooted.release();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AbstractAsyncExecutor.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AbstractAsyncExecutor.java
new file mode 100644
index 00000000..fc99cb05
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AbstractAsyncExecutor.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.AbstractAsyncExecutor
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/17 涓婂崍11:16
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.jd.blockchain.stp.communication.callback.CallBackLauncher;
+
+import java.util.concurrent.*;
+
+/**
+ * 鎶借薄寮傛鎵ц鍣
+ * @author shaozhuguang
+ * @create 2019/4/17
+ * @since 1.0.0
+ */
+
+public abstract class AbstractAsyncExecutor implements AsyncExecutor{
+
+ /**
+ * 绾跨▼姹犲彲澶勭悊闃熷垪鐨勫閲
+ */
+ private static final int QUEUE_CAPACITY = 1024;
+
+ /**
+ * 鍥炶皟鎵ц鍣
+ */
+ protected final CallBackLauncher callBackLauncher = new CallBackLauncher();
+
+ /**
+ * 榛樿鎻愪緵鐨勫垵濮嬪寲娲昏穬绾跨▼璋冨害鍣
+ * @return
+ */
+ @Override
+ public ThreadPoolExecutor initRunThread() {
+ ThreadFactory timerFactory = new ThreadFactoryBuilder()
+ .setNameFormat(threadNameFormat()).build();
+
+ ThreadPoolExecutor runThread = new ThreadPoolExecutor(1, 1,
+ 60, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(QUEUE_CAPACITY),
+ timerFactory,
+ new ThreadPoolExecutor.AbortPolicy());
+
+ return runThread;
+ }
+
+ /**
+ * 鍚姩瀹屾垚鍚庡洖璋
+ * 璇ヨ皟鐢ㄤ細闃诲褰撳墠绾跨▼锛岀洿鍒板惎鍔ㄥ畬鎴愶紝鏃犺鏄垚鍔熸垨澶辫触
+ * @return
+ * 鍥炶皟鎵ц鍣
+ * 鎴愬姛鎴栧け璐ヤ細鍦ㄥ洖璋冩墽琛屽櫒涓湁鎵浣撶幇
+ * @throws InterruptedException
+ */
+ @Override
+ public CallBackLauncher waitBooted() throws InterruptedException {
+ return callBackLauncher.waitingBooted();
+ }
+
+ /**
+ * 绾跨▼姹犱腑鐨勭嚎绋嬪懡鍚嶆牸寮
+ * @return
+ */
+ public abstract String threadNameFormat();
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AsyncExecutor.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AsyncExecutor.java
new file mode 100644
index 00000000..5bfdd682
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/AsyncExecutor.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.AsyncExecutor
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/17 涓婂崍11:14
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection;
+
+import com.jd.blockchain.stp.communication.callback.CallBackLauncher;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 寮傛鎵ц鍣ㄦ帴鍙
+ * @author shaozhuguang
+ * @create 2019/4/17
+ * @since 1.0.0
+ */
+
+public interface AsyncExecutor {
+
+ /**
+ * 鍒濆鍖栬繍琛岀嚎绋
+ * @return
+ */
+ ThreadPoolExecutor initRunThread();
+
+ /**
+ * 鍚姩瀹屾垚鍚庤繑鍥炶皟搴︽墽琛屽櫒
+ * @return
+ * @throws InterruptedException
+ */
+ CallBackLauncher waitBooted() throws InterruptedException;
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Connection.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Connection.java
new file mode 100644
index 00000000..5d534686
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Connection.java
@@ -0,0 +1,220 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.Connection
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓嬪崍5:39
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection;
+
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.callback.CallBackBarrier;
+import com.jd.blockchain.stp.communication.callback.CallBackDataListener;
+import com.jd.blockchain.stp.communication.callback.CallBackLauncher;
+import com.jd.blockchain.stp.communication.connection.listener.ReplyListener;
+import com.jd.blockchain.stp.communication.message.LoadMessage;
+import com.jd.blockchain.stp.communication.message.SessionMessage;
+import com.jd.blockchain.stp.communication.message.TransferMessage;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import java.util.Random;
+
+/**
+ * 缁熶竴杩炴帴瀵硅薄
+ * 璇ュ璞′腑鏈変袱涓璞eceiver鍜孲ender
+ * Receiver涓哄鐢ㄥ璞★紙姣忎釜绔彛鐩戝惉浜х敓鐨凴eceiver鍙湁涓涓級
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ * @date 2019-04-18 14:49
+ */
+public class Connection {
+
+ /**
+ * 杩滅鑺傜偣
+ */
+ private RemoteNode remoteNode;
+
+ /**
+ * 鎺ユ敹鍣
+ */
+ private Receiver receiver;
+
+ /**
+ * 鍙戦佸櫒
+ */
+ private Sender sender;
+
+ /**
+ * 鏋勯犲櫒
+ *
+ * @param receiver
+ */
+ public Connection(Receiver receiver) {
+ this.receiver = receiver;
+ }
+
+ /**
+ * 鍒濆鍖朢emoteSession
+ *
+ * @param remoteSession
+ */
+ public void initSession(RemoteSession remoteSession) {
+ this.receiver.initRemoteSession(remoteSession.remoteSessionId(), remoteSession);
+ }
+
+ /**
+ * 杩炴帴杩滅
+ *
+ * @param remoteNode
+ * 杩滅鑺傜偣
+ * @param messageExecutorClass
+ * 甯屾湜杩滅鑺傜偣澶勭悊鏈湴鑺傜偣娑堟伅鏃剁殑娑堟伅澶勭悊鍣
+ * @return
+ * 鍥炶皟鎵ц鍣
+ * @throws InterruptedException
+ */
+ public CallBackLauncher connect(RemoteNode remoteNode, String messageExecutorClass) throws InterruptedException {
+ this.remoteNode = remoteNode;
+ this.sender = new Sender(this.receiver.localNode(), this.remoteNode, sessionMessage(messageExecutorClass));
+ this.sender.connect();
+ return this.sender.waitBooted();
+ }
+
+ /**
+ * 鍙戦佽姹
+ *
+ * 澶勭悊杩囩▼绠杩板涓嬶細
+ * 1銆佺敓鎴愬簳灞傛秷鎭紙TransferMessage锛夛紝鍏朵腑娑堟伅绫诲瀷涓鸿姹傦紝鐢ㄤ簬鎻忚堪鏈鍙戦佺殑娑堟伅鏄敤浜庤姹傚簲绛旓紱
+ * 2銆佹牴鎹秷鎭殑鍞竴Key锛岀敓鎴恖istenKey锛屽苟鐢熸垚搴旂瓟鐩戝惉鍣
+ * 3銆佸皢搴旂瓟鐩戝惉鍣ㄦ坊鍔犲埌Receiver涓紙Receiver涓槸浠ap瀛樺偍锛
+ * 4銆佽皟鐢⊿ender鍙戦佹秷鎭嚦瀵圭鑺傜偣
+ * 5銆佽繑鍥炲簲绛旂洃鍚櫒鐨勫洖璋冩暟鎹洃鍚璞
+ *
+ * @param sessionId
+ * 褰撳墠SessionId
+ * @param loadMessage
+ * 杞戒綋娑堟伅
+ * @param callBackBarrier
+ * 鍥炶皟鏍呮爮
+ * @return
+ */
+ public CallBackDataListener request(String sessionId, LoadMessage loadMessage, CallBackBarrier callBackBarrier) {
+
+ TransferMessage transferMessage = transferMessage(sessionId, null, loadMessage, TransferMessage.MESSAGE_TYPE.TYPE_REQUEST);
+
+ // 鐩戝惉鍣ㄧ殑Key
+ String listenKey = transferMessage.toListenKey();
+
+ // 鍒涘缓鐩戝惉鍣
+ ReplyListener replyListener = new ReplyListener(listenKey, this.remoteNode, callBackBarrier);
+
+ // 娣诲姞鐩戝惉鍣ㄨ嚦Receiver
+ this.receiver.addListener(replyListener);
+
+ // 鍙戦佽姹
+ this.sender.send(transferMessage);
+
+ return replyListener.callBackDataListener();
+ }
+
+ /**
+ * 鍙戦佸簲绛
+ *
+ * @param sessionId
+ * 褰撳墠SessionID
+ * @param key
+ * 璇锋眰娑堟伅鐨凨ey锛岀敤浜庢弿杩板搴旂殑璇锋眰
+ * @param loadMessage
+ * 搴旂瓟鐨勮浇浣撴秷鎭
+ */
+ public void reply(String sessionId, String key, LoadMessage loadMessage) {
+ TransferMessage transferMessage = transferMessage(sessionId, key, loadMessage, TransferMessage.MESSAGE_TYPE.TYPE_RESPONSE);
+
+ // 閫氳繃Sender鍙戦佹暟鎹
+ this.sender.send(transferMessage);
+ }
+
+ /**
+ * 鐢熸垚杞戒綋娑堟伅鐨凨ey
+ *
+ * @param loadMessage
+ * @return
+ */
+ private String loadKey(LoadMessage loadMessage) {
+ // key姣忔涓嶈兘涓鑷达紝鍥犳澧炲姞闅忔満鏁
+ byte[] randomBytes = new byte[8];
+ new Random().nextBytes(randomBytes);
+ byte[] loadBytes = loadMessage.toBytes();
+ byte[] keyBytes = new byte[loadBytes.length + randomBytes.length];
+ System.arraycopy(randomBytes, 0, keyBytes, 0, randomBytes.length);
+ System.arraycopy(loadBytes, 0, keyBytes, randomBytes.length, loadBytes.length);
+ // 浣跨敤Sha256姹侶ash
+ byte[] sha256Bytes = DigestUtils.sha256(keyBytes);
+ // 浣跨敤base64浣滀负Key
+ return Base64.encodeBase64String(sha256Bytes);
+ }
+
+ /**
+ * 鐢熸垚TransferMessage
+ *
+ * @param sessionId
+ * 鑺傜偣ID
+ * @param key
+ * 娑堟伅Key
+ * @param loadMessage
+ * 杞戒綋娑堟伅
+ * @param messageType
+ * 娑堟伅绫诲瀷
+ * @return
+ */
+ private TransferMessage transferMessage(String sessionId, String key, LoadMessage loadMessage, TransferMessage.MESSAGE_TYPE messageType) {
+
+ if (key == null || key.length() == 0) {
+ key = loadKey(loadMessage);
+ }
+
+ TransferMessage transferMessage = new TransferMessage(
+ sessionId, messageType.code(), key, loadMessage.toBytes());
+
+ return transferMessage;
+ }
+
+ /**
+ * 鐢熸垚SessionMessage
+ *
+ * @param messageExecutorClass
+ *
+ * @return
+ */
+ private SessionMessage sessionMessage(String messageExecutorClass) {
+
+ LocalNode localNode = this.receiver.localNode();
+
+ SessionMessage sessionMessage = new SessionMessage(
+ localNode.getHostName(), localNode.getPort(), messageExecutorClass);
+
+ return sessionMessage;
+ }
+
+ public void closeAll() {
+ closeReceiver();
+ closeSender();
+ }
+
+ public RemoteNode remoteNode() {
+ return remoteNode;
+ }
+
+ public void closeReceiver() {
+ this.receiver.close();
+ }
+
+ public void closeSender() {
+ this.sender.close();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Receiver.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Receiver.java
new file mode 100644
index 00000000..fdbb0df6
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Receiver.java
@@ -0,0 +1,161 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.inner.Receiver
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍10:59
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection;
+
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.connection.handler.HeartBeatReceiverHandler;
+import com.jd.blockchain.stp.communication.connection.handler.HeartBeatReceiverTrigger;
+import com.jd.blockchain.stp.communication.connection.handler.ReceiverHandler;
+import com.jd.blockchain.stp.communication.connection.listener.ReplyListener;
+import com.jd.blockchain.stp.communication.manager.ConnectionManager;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+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.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.io.Closeable;
+import java.net.InetSocketAddress;
+import java.util.concurrent.*;
+
+/**
+ * 鎺ユ敹鍣
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+
+public class Receiver extends AbstractAsyncExecutor implements Closeable {
+
+ /**
+ * Netty涓殑BOSS绾跨▼
+ */
+ private final EventLoopGroup bossGroup = new NioEventLoopGroup();
+
+ /**
+ * Netty涓殑Worker绾跨▼
+ */
+ private final EventLoopGroup workerGroup = new NioEventLoopGroup();
+
+ /**
+ * 鏈湴鑺傜偣
+ */
+ private LocalNode localNode;
+
+ /**
+ * 娑堟伅鎺ユ敹Handler
+ */
+ private ReceiverHandler receiverHandler;
+
+ public Receiver(LocalNode localNode) {
+ this.localNode = localNode;
+ }
+
+ /**
+ * 鍚姩鐩戝惉
+ */
+ public void startListen() {
+ ServerBootstrap bootstrap = new ServerBootstrap();
+
+ bootstrap.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .option(ChannelOption.SO_BACKLOG, 1024)
+ .childOption(ChannelOption.SO_KEEPALIVE, true)
+ .localAddress(new InetSocketAddress(this.localNode.getPort()))
+ .childHandler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel socketChannel) throws Exception {
+ socketChannel.pipeline()
+// .addLast(new LoggingHandler(LogLevel.ERROR))
+ .addLast(new IdleStateHandler(8, 0, 0, TimeUnit.SECONDS))
+ .addLast(new LineBasedFrameDecoder(1024))
+ .addLast(new StringDecoder())
+ .addLast(new HeartBeatReceiverTrigger())
+ .addLast(new HeartBeatReceiverHandler())
+ .addLast(receiverHandler);
+ }
+ });
+
+ // 鐢卞崟鐙殑绾跨▼鍚姩锛岄槻姝㈠閮ㄨ皟鐢ㄧ嚎绋嬮樆濉
+ ThreadPoolExecutor runThread = initRunThread();
+ runThread.execute(() -> {
+ try {
+ ChannelFuture f = bootstrap.bind().sync();
+ boolean isStartSuccess = f.isSuccess();
+ if (isStartSuccess) {
+ super.callBackLauncher.bootSuccess();
+ // 鍚姩鎴愬姛
+ f.channel().closeFuture().sync();
+ } else {
+ // 鍚姩澶辫触
+ throw new Exception("Receiver start fail :" + f.cause().getMessage() + " !!!");
+ }
+ } catch (Exception e) {
+ super.callBackLauncher.bootFail(e);
+ } finally {
+ close();
+ }
+ });
+ }
+
+ @Override
+ public String threadNameFormat() {
+ return "receiver-pool-%d";
+ }
+
+ /**
+ * 鍒濆鍖朢eceiverHandler
+ *
+ * @param connectionManager
+ * 杩炴帴绠$悊鍣
+ * @param messageExecutorClass
+ * 褰撳墠鑺傜偣鐨勬秷鎭鐞咰lass
+ */
+ public void initReceiverHandler(ConnectionManager connectionManager, String messageExecutorClass) {
+ receiverHandler = new ReceiverHandler(connectionManager, messageExecutorClass, this.localNode);
+ }
+
+ /**
+ * 鍒濆鍖栬繙绔疭ession
+ *
+ * @param sessionId
+ *
+ * @param remoteSession
+ */
+ public void initRemoteSession(String sessionId, RemoteSession remoteSession) {
+ receiverHandler.putRemoteSession(sessionId, remoteSession);
+ }
+
+ /**
+ * 娣诲姞鐩戝惉鍣
+ *
+ * @param replyListener
+ */
+ public void addListener(ReplyListener replyListener) {
+ receiverHandler.addListener(replyListener);
+ }
+
+ @Override
+ public void close() {
+ receiverHandler.close();
+ bossGroup.shutdownGracefully();
+ workerGroup.shutdownGracefully();
+ }
+
+ public LocalNode localNode() {
+ return this.localNode;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Sender.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Sender.java
new file mode 100644
index 00000000..7c17f18f
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/Sender.java
@@ -0,0 +1,207 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.inner.Sender
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍10:58
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection;
+
+import com.jd.blockchain.stp.communication.connection.handler.*;
+import com.jd.blockchain.stp.communication.message.IMessage;
+import com.jd.blockchain.stp.communication.message.SessionMessage;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.codec.string.StringDecoder;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * 鍙戦佸櫒
+ *
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ * @date 2019-04-18 15:08
+ */
+public class Sender extends AbstractAsyncExecutor implements Closeable {
+
+ private final EventLoopGroup loopGroup = new NioEventLoopGroup();
+
+ private Bootstrap bootstrap;
+
+ private ChannelFuture channelFuture;
+
+ /**
+ * 褰撳墠鑺傜偣鐨凷essionMessage
+ */
+ private SessionMessage sessionMessage;
+
+ private LocalNode localNode;
+
+ private RemoteNode remoteNode;
+
+// /**
+// * 杩滅HOST
+// */
+// private String remoteHost;
+//
+// /**
+// * 杩滅绔彛
+// */
+// private int remotePort;
+
+ /**
+ * 鐩戝惉Handler锛堥噸杩濰andler锛
+ */
+ private WatchDogHandler watchDogHandler;
+
+ public Sender(LocalNode localNode, RemoteNode remoteNode, SessionMessage sessionMessage) {
+ init(localNode, remoteNode, sessionMessage);
+ }
+
+// public Sender(String remoteHost, int remotePort, SessionMessage sessionMessage) {
+// init(remoteHost, remotePort, sessionMessage);
+// }
+
+ /**
+ * 杩炴帴
+ */
+ public void connect() {
+ watchDogHandler = new WatchDogHandler(this.remoteNode.getHostName(), this.remoteNode.getPort(), bootstrap);
+
+ ChannelHandlers frontChannelHandlers = new ChannelHandlers()
+ .addHandler(watchDogHandler);
+
+ ChannelHandlers afterChannelHandlers = new ChannelHandlers()
+ .addHandler(new StringDecoder())
+ .addHandler(new HeartBeatSenderTrigger())
+ .addHandler(new HeartBeatSenderHandler())
+ .addHandler(new SenderHandler(this.localNode, this.remoteNode, this.sessionMessage));
+
+ // 鍒濆鍖杦atchDogHandler
+ watchDogHandler.init(frontChannelHandlers.toArray(), afterChannelHandlers.toArray());
+
+ bootstrap.handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ch.pipeline()
+ .addLast(frontChannelHandlers.toArray())
+ .addLast(new IdleStateHandler(10, 4, 0, TimeUnit.SECONDS))
+ .addLast(new LineBasedFrameDecoder(1024))
+ .addLast(afterChannelHandlers.toArray());
+ }
+ });
+
+ ThreadPoolExecutor runThread = initRunThread();
+
+ // 鍗曠嫭绾跨▼杩涜杩炴帴锛岄槻姝㈠綋鍓嶈皟鐢ㄧ嚎绋嬮樆濉
+ runThread.execute(() -> {
+ try {
+ // 鍙戣捣杩炴帴璇锋眰
+ channelFuture = bootstrap.connect(this.remoteNode.getHostName(), this.remoteNode.getPort()).sync();
+ boolean isStartSuccess = channelFuture.isSuccess();
+ if (isStartSuccess) {
+ // 鍚姩鎴愬姛
+ // 璁剧疆ChannelFuture瀵硅薄锛屼互渚夸簬鍙戦佺殑杩炴帴鐘舵佸鐞
+ watchDogHandler.initChannelFuture(channelFuture);
+ // 閲婃斁绛夊緟
+ super.callBackLauncher.bootSuccess();
+ // 绛夊緟瀹㈡埛绔叧闂繛鎺
+ channelFuture.channel().closeFuture().sync();
+ } else {
+ // 鍚姩澶辫触
+ throw new Exception("Sender start fail :" + channelFuture.cause().getMessage() + " !!!");
+ }
+ } catch (Exception e) {
+ super.callBackLauncher.bootFail(e);
+ } finally {
+ close();
+ }
+ });
+ }
+
+ /**
+ * 鍒濆鍖栫浉鍏抽厤缃
+ *
+ * @param localNode
+ * 鏈湴鑺傜偣
+ * @param remoteNode
+ * 杩滅鑺傜偣
+ * @param sessionMessage
+ * 鏈湴鑺傜偣杩炴帴鍒拌繙绔妭鐐瑰悗鍙戦佺殑SessionMessage
+ */
+ private void init(LocalNode localNode, RemoteNode remoteNode, SessionMessage sessionMessage) {
+ this.localNode = localNode;
+ this.remoteNode = remoteNode;
+
+ this.sessionMessage = sessionMessage;
+
+ this.bootstrap = new Bootstrap().group(loopGroup)
+ .channel(NioSocketChannel.class)
+ .option(ChannelOption.SO_KEEPALIVE, true)
+ .option(ChannelOption.TCP_NODELAY, true);
+ }
+
+ @Override
+ public String threadNameFormat() {
+ return "sender-pool-%d";
+ }
+
+ /**
+ * 鍙戦佹秷鎭
+ *
+ * @param message
+ * 娑堟伅缁熶竴鎺ュ彛
+ */
+ public void send(IMessage message) {
+ watchDogHandler.channelFuture().channel().writeAndFlush(message.toTransferByteBuf());
+ }
+
+ @Override
+ public void close() {
+ // 鍥犱负瑕侀噸杩烇紝闇瑕佷粛鐒堕渶瑕佷娇鐢ㄨLoopGroup锛屽洜姝や笉鑳藉叧闂
+// loopGroup.shutdownGracefully();
+ }
+
+ /**
+ * ChannelHandler闆嗗悎绠$悊绫
+ */
+ public static class ChannelHandlers {
+
+ private List channelHandlers = new ArrayList<>();
+
+ /**
+ * 娣诲姞鎸囧畾鐨凜hannelHandler
+ *
+ * @param channelHandler
+ * 闇瑕佸姞鍏ョ殑ChannelHandler
+ * @return
+ */
+ public ChannelHandlers addHandler(ChannelHandler channelHandler) {
+ channelHandlers.add(channelHandler);
+ return this;
+ }
+
+ /**
+ * List闆嗗悎杞崲涓烘暟缁
+ *
+ * @return
+ */
+ public ChannelHandler[] toArray() {
+ ChannelHandler[] channelHandlerArray = new ChannelHandler[channelHandlers.size()];
+ return channelHandlers.toArray(channelHandlerArray);
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverHandler.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverHandler.java
new file mode 100644
index 00000000..ab3595e9
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverHandler.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.HeartBeatSenderHandler
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/15 涓婂崍10:10
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.jd.blockchain.stp.communication.message.HeartBeatMessage;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * 蹇冭烦鎺ユ敹Handler
+ * @author shaozhuguang
+ * @create 2019/4/15
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class HeartBeatReceiverHandler extends ChannelInboundHandlerAdapter {
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ // 鍒ゆ柇褰撳墠鏀跺埌鐨勪俊鎭槸鍚︿负蹇冭烦淇℃伅
+ if (HeartBeatMessage.isHeartBeat(msg)) {
+ // 鏀跺埌鐨勬秷鎭槸蹇冭烦娑堟伅锛屾鏃堕渶瑕佸洖澶嶄竴涓績璺虫秷鎭
+ HeartBeatMessage.write(ctx);
+ System.out.println("Receive HeartBeat Request Message -> " + msg.toString());
+ } else {
+ // 闈炲績璺充俊鎭殑鎯呭喌涓嬩氦鐢卞叾浠朒andler缁х画澶勭悊
+ super.channelRead(ctx, msg);
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ // 鍑虹幇寮傚父鐩存帴鍏抽棴杩炴帴
+ ctx.close();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverTrigger.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverTrigger.java
new file mode 100644
index 00000000..48288dc6
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatReceiverTrigger.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.HeartBeatSenderTrigger
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/15 涓婂崍10:11
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+
+/**
+ * 蹇冭烦鎺ユ敹瑙﹀彂鍣
+ * @author shaozhuguang
+ * @create 2019/4/15
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class HeartBeatReceiverTrigger extends ChannelInboundHandlerAdapter {
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+ // 鏈嶅姟绔彧浼氭帴鏀跺績璺虫暟鎹悗搴旂瓟锛岃屼笉浼氫富鍔ㄥ簲绛
+ if (evt instanceof IdleStateEvent) {
+ IdleState idleState = ((IdleStateEvent) evt).state();
+ // 璇昏姹傝秴鏃惰〃绀哄緢涔呮病鏈夋敹鍒板鎴风璇锋眰
+ if (idleState.equals(IdleState.READER_IDLE)) {
+ // 闀挎椂闂存湭鏀跺埌瀹㈡埛绔姹傦紝鍒欏叧闂繛鎺
+ System.out.println("Long Time UnReceive HeartBeat Request, Close Connection !!!");
+ ctx.close();
+ }
+ } else {
+ // 闈炵┖闂茬姸鎬佷簨浠讹紝鐢卞叾浠朒andler澶勭悊
+ super.userEventTriggered(ctx, evt);
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderHandler.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderHandler.java
new file mode 100644
index 00000000..be1c187b
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderHandler.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.HeartBeatSenderHandler
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/15 涓婂崍10:10
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.jd.blockchain.stp.communication.message.HeartBeatMessage;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+/**
+ * 蹇冭烦鍙戦丠andler
+ * @author shaozhuguang
+ * @create 2019/4/15
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class HeartBeatSenderHandler extends ChannelInboundHandlerAdapter {
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ // 鍒ゆ柇鏀跺埌鐨勬秷鎭
+ if (HeartBeatMessage.isHeartBeat(msg)) {
+ // 鍋囪鏀跺埌鐨勬秷鎭槸瀛楃涓诧紝骞朵笖鏄績璺虫秷鎭紝璇存槑鐢辨湇鍔$鍙戦佷簡蹇冭烦淇℃伅
+ // TODO 姝ゅ涓嶉渶瑕佽繘琛屾秷鎭弽棣堬紝鍙渶瑕佹墦鍗版棩蹇楀嵆鍙
+ System.out.println("Receive HeartBeat Response Message -> " + msg.toString());
+ } else {
+ super.channelRead(ctx, msg);
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ // 鍑虹幇寮傚父鐩存帴鍏抽棴杩炴帴
+ ctx.close();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderTrigger.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderTrigger.java
new file mode 100644
index 00000000..9a61f31a
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/HeartBeatSenderTrigger.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.HeartBeatSenderTrigger
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/15 涓婂崍10:11
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.jd.blockchain.stp.communication.message.HeartBeatMessage;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleState;
+import io.netty.handler.timeout.IdleStateEvent;
+
+/**
+ * 蹇冭烦鍙戦佽Е鍙戝櫒
+ * @author shaozhuguang
+ * @create 2019/4/15
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class HeartBeatSenderTrigger extends ChannelInboundHandlerAdapter {
+
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
+
+ // 蹇冭烦浜嬩欢锛堢姸鎬佺┖闂蹭簨浠讹級
+ if (evt instanceof IdleStateEvent) {
+ IdleState idleState = ((IdleStateEvent) evt).state();
+ if (idleState.equals(IdleState.READER_IDLE)) {
+ // Sender璇昏秴鏃讹紝琛ㄧず鍦ㄦ寚瀹氭椂闂村唴鏈敹鍒癛eceiver鐨勫簲绛
+ // 姝ゆ椂鍏抽棴杩炴帴锛岃嚜鍔ㄨ皟鐢ㄩ噸杩炴満鍒讹紝杩涜閲嶈繛鎿嶄綔
+ System.out.println("Long Time UnReceive HeartBeat Response, Close Connection !!!");
+ ctx.close();
+ } else if (idleState == IdleState.WRITER_IDLE) {
+ // Sender鍐欒秴鏃讹紝琛ㄧず寰堥暱鏃堕棿娌℃湁鍙戦佹秷鎭簡锛岄渶瑕佸彂閫佹秷鎭嚦Receiver
+ System.out.println("Read TimeOut Trigger, Send HeartBeat Request !!!");
+ HeartBeatMessage.write(ctx);
+ }
+ // TODO 杩樻湁涓绉嶆儏鍐垫槸璇诲啓瓒呮椂锛岃鎯呭喌鏆備笉澶勭悊
+ } else {
+ super.userEventTriggered(ctx, evt);
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/ReceiverHandler.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/ReceiverHandler.java
new file mode 100644
index 00000000..0dcf6753
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/ReceiverHandler.java
@@ -0,0 +1,345 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.ReceiverHandler
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/12 涓婂崍11:14
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.jd.blockchain.stp.communication.MessageExecutor;
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.connection.Connection;
+import com.jd.blockchain.stp.communication.connection.listener.ReplyListener;
+import com.jd.blockchain.stp.communication.manager.ConnectionManager;
+import com.jd.blockchain.stp.communication.message.SessionMessage;
+import com.jd.blockchain.stp.communication.message.TransferMessage;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.apache.commons.codec.binary.Hex;
+
+import java.io.Closeable;
+import java.util.Map;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 鎺ユ敹鑰呮秷鎭鐞咹andler
+ * @author shaozhuguang
+ * @create 2019/4/12
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class ReceiverHandler extends ChannelInboundHandlerAdapter implements Closeable {
+
+ /**
+ * 闃熷垪鐨勬渶澶у閲忚缃紝榛樿涓256K锛堥槻姝㈤槦鍒楁孩鍑猴級
+ */
+ private static final int QUEUE_CAPACITY = 256 * 1024;
+
+ /**
+ * 杩滅RemoteSession淇℃伅闆嗗悎
+ * Key涓篠essionId
+ * Sender鍙戦佺殑娑堟伅涓細鎼哄甫SessionId
+ * ReceiverHandler浼氭牴鎹笉鍚岀殑SessionId閲囩敤涓嶅悓鐨凪essageExecutor澶勭悊绛栫暐
+ */
+ private final Map remoteSessions = new ConcurrentHashMap<>();
+
+ /**
+ * 鐩戝惉鍣ㄩ泦鍚
+ * 瀵瑰簲Sender鍦ㄥ彂閫佽姹備箣鍓嶄細璁剧疆ReplyListener
+ * Key涓烘瘡涓姹傛秷鎭殑Hash锛岀敤浜庢弿杩版秷鎭殑鍞竴鎬
+ * 搴旂瓟涓鏂逛細鍦ㄥ簲绛斾腑鍔犲叆瀵瑰簲鐨刱ey锛岀敤浜庢秷鎭殑鏄犲皠
+ */
+ private final Map allReplyListeners = new ConcurrentHashMap<>();
+
+ /**
+ * session鎺у埗閿
+ * 鐢ㄤ簬闃叉瀵圭粺涓RemoteSession瀵硅薄杩涜閲嶅璁剧疆
+ */
+ private final Lock sessionLock = new ReentrantLock();
+
+ /**
+ * 褰撳墠鑺傜偣锛堟湰鍦拌妭鐐癸級鐨勬秷鎭鐞嗗櫒瀵瑰簲Class
+ * 璇ヤ俊鎭敤浜庡彂閫佽嚦鍏朵粬鑺傜偣锛屽悜鍏朵粬鑺傜偣閫氱煡閬囧埌鏈妭鐐硅姹傛椂璇ュ浣曞鐞
+ */
+ private String localMsgExecutorClass;
+
+ /**
+ * 杩炴帴鎺у埗鍣紝鐢ㄤ簬涓庤繙绔妭鐐硅繛鎺
+ */
+ private ConnectionManager connectionManager;
+
+ /**
+ * 娑堟伅澶勭悊鎵ц绾跨▼姹
+ * 闃叉鎵ц鍐呭杩囬暱锛屽鑷撮樆濉
+ */
+ private ExecutorService msgExecutorPool;
+
+ /**
+ * 榛樿娑堟伅澶勭悊鍣
+ * 褰撳搴攕ession鑾峰彇鍒扮殑RemoteSession涓病鏈夎幏鍙栧埌鎸囧畾MessageExecutor鏃讹紝鐭椂闂村唴鐢卞叾杩涜澶勭悊
+ */
+ private MessageExecutor defaultMessageExecutor;
+
+ /**
+ * 鏈湴鑺傜偣
+ */
+ private LocalNode localNode;
+
+ public ReceiverHandler(ConnectionManager connectionManager, String localMsgExecutorClass,
+ LocalNode localNode) {
+ this.connectionManager = connectionManager;
+ this.localMsgExecutorClass = localMsgExecutorClass;
+ this.defaultMessageExecutor = localNode.defaultMessageExecutor();
+ this.localNode = localNode;
+ initMsgExecutorPool();
+ }
+
+ public void putRemoteSession(String sessionId, RemoteSession remoteSession) {
+ remoteSessions.put(sessionId, remoteSession);
+ }
+
+ public void addListener(ReplyListener replyListener) {
+ allReplyListeners.put(replyListener.listenKey(), replyListener);
+ }
+
+ public void removeListener(String key) {
+ this.allReplyListeners.remove(key);
+ }
+
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+
+ System.out.printf("%s Receive Biz Message -> %s \r\n", this.localNode.toString(), msg.toString());
+ // 鏈夋暟鎹帴鍏
+ // 棣栧厛鍒ゆ柇鏁版嵁鏄惁TransferMessage锛屽綋鍓岺andler涓嶅鐞嗛潪TransferMessage
+ TransferMessage tm = TransferMessage.toTransferMessage(msg);
+ if (tm == null) {
+ // 鍒ゆ柇鏄惁鏄疭essionMessage
+ SessionMessage sm = SessionMessage.toSessionMessage(msg);
+ if (sm != null) {
+ executeSessionMessage(sm);
+ } else {
+ super.channelRead(ctx, msg);
+ }
+ } else {
+ TransferMessage.MESSAGE_TYPE messageType = TransferMessage.MESSAGE_TYPE.valueOf(tm.getType());
+ // 瀵逛簬璇锋眰鍜屽簲绛斿鐞嗘柟寮忎笉鍚
+ if (messageType.equals(TransferMessage.MESSAGE_TYPE.TYPE_REQUEST)) {
+ // 鍋囪鏄姹傛秷鎭
+ executeRequest(tm);
+ } else if (messageType.equals(TransferMessage.MESSAGE_TYPE.TYPE_RESPONSE)) {
+ // 鍋囪鏄簲绛旀秷鎭
+ executeResponse(tm);
+ } else {
+ // todo 鍏朵粬娑堟伅鍙渶瑕佹墦鍗版棩蹇楀嵆鍙
+
+
+ }
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ ctx.close();
+ }
+
+ /**
+ * 澶勭悊璇锋眰娑堟伅
+ *
+ * @param transferMessage
+ * 鎺ユ敹鍒扮殑璇锋眰娑堟伅
+ */
+ private void executeRequest(final TransferMessage transferMessage) {
+ msgExecutorPool.execute(() -> {
+ RemoteSession remoteSession = remoteSessions.get(transferMessage.getSessionId());
+ if (remoteSession != null) {
+ MessageExecutor messageExecutor = remoteSession.messageExecutor();
+ if (messageExecutor == null) {
+ // 閲囩敤榛樿澶勭悊鍣ㄨ繘琛屽鐞
+ messageExecutor = defaultMessageExecutor;
+ }
+ MessageExecutor.REPLY replyType = messageExecutor.replyType();
+ if (replyType != null) {
+ switch (replyType) {
+ case MANUAL:
+ messageExecutor.receive(transferMessage.loadKey(), transferMessage.load(), remoteSession);
+ break;
+ case AUTO:
+ String requestKey = transferMessage.loadKey();
+ byte[] replyMsg = messageExecutor.receive(requestKey, transferMessage.load(), remoteSession);
+ // 搴旂瓟
+ remoteSession.reply(requestKey, () -> replyMsg);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 澶勭悊搴旂瓟娑堟伅
+ * @param transferMessage
+ * 鎺ユ敹鍒扮殑搴旂瓟娑堟伅
+ */
+ private void executeResponse(final TransferMessage transferMessage) {
+ msgExecutorPool.execute(() -> {
+ // listenKey鍜宮sgKey鏄笉涓鑷寸殑
+ // msgKey鏄娑堟伅鏈韩璁剧疆key锛宭istenKey鏄鏁翠釜娑堟伅锛堝寘鎷瑂ession淇℃伅锛
+ String listenKey = transferMessage.toListenKey();
+
+ ReplyListener replyListener = allReplyListeners.get(listenKey);
+
+ if (replyListener != null) {
+ // 濉厖瀵瑰簲鐨勭粨鏋
+ replyListener.replyData(transferMessage.load());
+
+ ReplyListener.MANAGE_TYPE manageType = replyListener.manageType();
+
+ if (manageType != null) {
+ switch (manageType) {
+ case REMOVE:
+ // 灏嗗璞′粠Map涓Щ闄
+ removeListener(listenKey);
+ break;
+ case HOLD:
+ default:
+ // todo 鎵撳嵃鏃ュ織
+
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 澶勭悊SessionMessage
+ * @param sessionMessage
+ * 鎻忚堪Session鐨勬秷鎭璞
+ */
+ private void executeSessionMessage(SessionMessage sessionMessage) {
+ // 澶勭悊SessionMessage
+ String sessionId = sessionMessage.sessionId();
+ if (sessionId != null) {
+ // 瀵逛簬鍚湁鐨凴emoteSession鐨凪ap锛岄渶瑕佸垽鏂叾MessageExecutor鏄惁涓篘ULL
+ RemoteSession remoteSession = remoteSessions.get(sessionId);
+ if (remoteSession == null) {
+ try {
+ sessionLock.lock();
+ // 鐢熸垚瀵瑰簲鐨凪essageExecute瀵硅薄
+ String meClass = sessionMessage.getMessageExecutor();
+ MessageExecutor messageExecutor = initMessageExecutor(meClass);
+
+ // 璇存槑灏氭湭鍜岃姹傛潵鐨勫鎴风寤虹珛杩炴帴锛岄渶瑕佸缓绔嬭繛鎺
+ Connection remoteConnection = this.connectionManager.connect(new RemoteNode(
+ sessionMessage.getLocalHost(), sessionMessage.getListenPort()),
+ this.localMsgExecutorClass);
+ // 鍋囪杩炴帴澶辫触鐨勮瘽锛岃繑鍥炵殑Connection瀵硅薄涓簄ull锛屾鏃朵笉鏀惧叆Map锛岀瓑鍚庣画鍐嶅鐞
+ if (remoteConnection != null) {
+
+ remoteSession = new RemoteSession(this.localId(), remoteConnection, messageExecutor);
+
+ // Double check 锛侊紒锛
+ if (!remoteSessions.containsKey(sessionId)) {
+ this.putRemoteSession(sessionId, remoteSession);
+ }
+ }
+ } finally {
+ sessionLock.unlock();
+ }
+ } else {
+ // 闇瑕佸垽鏂璏essageExecutor
+ MessageExecutor me = remoteSession.messageExecutor();
+ if (me == null) {
+ try {
+ sessionLock.lock();
+ // Double Check !!!
+ if (remoteSession.messageExecutor() == null) {
+ // 琛ㄦ槑涓婃瀛樺偍鐨凪essageExecutor鏈垱寤烘垚鍔燂紝鏈杩涜鏇存柊
+ String meClass = sessionMessage.getMessageExecutor();
+ MessageExecutor messageExecutor = initMessageExecutor(meClass);
+
+ // 闃叉NULL灏嗗叾浠栫殑杩涜瑕嗙洊
+ if (messageExecutor != null) {
+ remoteSession.initExecutor(messageExecutor);
+ }
+ }
+ } finally {
+ sessionLock.unlock();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 鍒濆鍖栨秷鎭墽琛屽櫒
+ * 鏍规嵁娑堟伅鎵ц鍣ㄧ殑Class瀛楃涓茬敓鎴愬搴旂殑娑堟伅澶勭悊瀵硅薄
+ * @param messageExecutorClass
+ * 娑堟伅鎵ц鍣ㄧ殑Class瀛楃涓
+ * @return
+ * 瀵瑰簲鐨勬秷鎭鐞嗗璞★紝浜х敓浠讳綍寮傚父閮借繑鍥濶ULL
+ */
+ private MessageExecutor initMessageExecutor(String messageExecutorClass) {
+ // 鐢熸垚瀵瑰簲鐨凪essageExecute瀵硅薄
+ MessageExecutor messageExecutor = null;
+ if (messageExecutorClass != null && messageExecutorClass.length() > 0) {
+ try {
+ Class> clazz = Class.forName(messageExecutorClass);
+ messageExecutor = (MessageExecutor) clazz.newInstance();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+ return messageExecutor;
+ }
+
+ /**
+ * 鍒濆鍖栨秷鎭鐞嗙嚎绋嬫睜
+ */
+ private void initMsgExecutorPool() {
+
+ ThreadFactory msgExecuteThreadFactory = new ThreadFactoryBuilder()
+ .setNameFormat("msg-executor-pool-%d").build();
+
+ //Common Thread Pool
+ msgExecutorPool = new ThreadPoolExecutor(5, 10,
+ 60, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(QUEUE_CAPACITY),
+ msgExecuteThreadFactory, new ThreadPoolExecutor.AbortPolicy());
+ }
+
+ /**
+ * 杩斿洖鏈湴鑺傜偣
+ *
+ * @return
+ */
+ public LocalNode localNode() {
+ return localNode;
+ }
+
+ /**
+ * 杩斿洖鏈湴鑺傜偣ID
+ *
+ * @return
+ */
+ private String localId() {
+ return Hex.encodeHexString(localNode.toString().getBytes());
+ }
+
+ @Override
+ public void close() {
+ msgExecutorPool.shutdown();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/SenderHandler.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/SenderHandler.java
new file mode 100644
index 00000000..ed763434
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/SenderHandler.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.handler.SenderHandler
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/16 涓嬪崍2:00
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.jd.blockchain.stp.communication.message.SessionMessage;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+
+/**
+ * Sender瀵瑰簲Handler
+ * @author shaozhuguang
+ * @create 2019/4/16
+ * @since 1.0.0
+ */
+@ChannelHandler.Sharable
+public class SenderHandler extends ChannelInboundHandlerAdapter {
+
+ /**
+ * 鏈湴session淇℃伅
+ */
+ private SessionMessage sessionMessage;
+
+ /**
+ * 鏈湴鑺傜偣
+ */
+ private LocalNode localNode;
+
+ /**
+ * 杩滅鑺傜偣
+ */
+ private RemoteNode remoteNode;
+
+ public SenderHandler(LocalNode localNode, RemoteNode remoteNode, SessionMessage sessionMessage) {
+ this.localNode = localNode;
+ this.remoteNode = remoteNode;
+ this.sessionMessage = sessionMessage;
+ }
+
+ /**
+ * 杩炴帴杩滅鑺傜偣鎴愬姛鏃惰Е鍙
+ *
+ * @param ctx
+ * @throws Exception
+ */
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+
+ // 鍙戦佹湰鏈轰俊鎭紙鍖呮嫭IP銆佺鍙g瓑锛夎嚦瀵圭
+ System.out.printf("%s Connect %s Success, Send Local Node Information !!! \r\n", this.localNode, this.remoteNode);
+ ctx.writeAndFlush(sessionMessage.toTransferByteBuf());
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ ctx.close();
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/WatchDogHandler.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/WatchDogHandler.java
new file mode 100644
index 00000000..bdcb82de
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/handler/WatchDogHandler.java
@@ -0,0 +1,267 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.SenderWatchDog
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/12 涓嬪崍4:56
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.handler;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.jd.blockchain.stp.communication.message.HeartBeatMessage;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.handler.codec.LineBasedFrameDecoder;
+import io.netty.handler.timeout.IdleStateHandler;
+
+import java.io.Closeable;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 杩炴帴鐩戝惉鍣
+ * @author shaozhuguang
+ * @create 2019/4/12
+ * @since 1.0.0
+ * @date 2019-04-19 09:21
+ */
+@ChannelHandler.Sharable
+public class WatchDogHandler extends ChannelInboundHandlerAdapter implements Runnable, Closeable {
+
+ /**
+ * 褰撳墠杩炴帴娲昏穬鐘舵
+ */
+ private final AtomicBoolean currentActive = new AtomicBoolean(false);
+
+ /**
+ * 閲嶈繛鐨勬帶鍒堕攣
+ * 闃叉閲嶈繛杩囩▼涓噸澶嶅娆¤皟鐢
+ */
+ private final Lock reconnectLock = new ReentrantLock();
+
+ /**
+ * 榛樿鐨勬渶澶氶噸杩炴鏁
+ */
+ private final int maxReconnectSize = 16;
+
+ /**
+ * 榛樿閲嶈繛鐨勬椂闂达紝涓嬫閲嶈繛鏃堕棿浼氬彉闀
+ */
+ private final int defaultReconnectSeconds = 2;
+
+ /**
+ * 鏍囪瘑鏄惁姝e父宸ヤ綔涓紝鍋囪涓嶅啀宸ヤ綔鍒欎笉鍐嶉噸杩
+ */
+ private boolean isWorking = true;
+
+ /**
+ * 閲嶈繛璋冨害鍣
+ */
+ private ScheduledExecutorService reconnectTimer;
+
+ /**
+ * 杩滅鐨処P锛堝煙鍚嶏級淇℃伅
+ */
+ private String hostName;
+
+ /**
+ * 杩滅鐨勭鍙
+ */
+ private int port;
+
+ private Bootstrap bootstrap;
+
+ /**
+ * 绗竴缁凥andler鏁扮粍
+ */
+ private ChannelHandler[] frontHandlers;
+
+ /**
+ * 鍚庝竴缁凥andler鏁扮粍
+ */
+ private ChannelHandler[] afterHandlers;
+
+ /**
+ * 鐢ㄤ簬閲嶈繛鏃跺璞¢噸缃
+ */
+ private ChannelFuture channelFuture;
+
+ /**
+ * 鏋勯犲櫒
+ * @param hostName
+ * 杩滅Host
+ * @param port
+ * 杩滅绔彛
+ * @param bootstrap
+ * Netty宸ヤ綔鍚姩鍣
+ */
+ public WatchDogHandler(String hostName, int port, Bootstrap bootstrap) {
+ this.hostName = hostName;
+ this.port = port;
+ this.bootstrap = bootstrap;
+ }
+
+ /**
+ * 鏋勯犲櫒
+ * @param remoteNode
+ * 杩滅鑺傜偣
+ * @param bootstrap
+ * Netty宸ヤ綔鍚姩鍣
+ */
+ public WatchDogHandler(RemoteNode remoteNode, Bootstrap bootstrap) {
+ this(remoteNode.getHostName(), remoteNode.getPort(), bootstrap);
+ }
+
+ /**
+ * 閰嶇疆閲嶈繛闇瑕佺殑Handler
+ * 涓昏鏄负浜嗗璞$殑澶嶇敤锛屽悓鏃舵湁浜汬andler鏃犳硶澶嶇敤锛屽浜庢瘡娆¤繛鎺ヨ姹傚繀椤昏new鏂扮殑瀵硅薄
+ * @param frontHandlers
+ * @param afterHandlers
+ */
+ public void init(ChannelHandler[] frontHandlers, ChannelHandler[] afterHandlers) {
+ this.frontHandlers = frontHandlers;
+ this.afterHandlers = afterHandlers;
+ initTimer();
+ }
+
+ /**
+ * 鍒濆鍖朇hannelFuture
+ *
+ * @param channelFuture
+ */
+ public void initChannelFuture(ChannelFuture channelFuture) {
+ this.channelFuture = channelFuture;
+ }
+
+ /**
+ * 杩斿洖ChannelFuture
+ *
+ * @return
+ * 璇ヨ繑鍥炲璞$洰鍓嶆湭澶勭悊鏄惁杩炴帴鎴愬姛鐨勬儏鍐
+ * 璋冪敤鑰呭彲鐩存帴浣跨敤锛屼絾鍋囪鍙戦佷笉鎴愬姛鐨勮瘽浼氬瓨鍦ㄥ紓甯告姏鍑
+ * 璋冪敤鑰呭彲鎵嬪姩澶勭悊寮傚父
+ */
+ public ChannelFuture channelFuture() {
+ try {
+ // 浣跨敤閿侀槻姝㈠湪閲嶈繛杩涜杩囩▼涓簰鐩哥珵浜
+ // 涓瀹氭槸绛夊緟鏈閲嶈繛瀹屾垚鎵嶈繑鍥
+ reconnectLock.lock();
+ return this.channelFuture;
+ } finally {
+ reconnectLock.unlock();
+ }
+ }
+
+ /**
+ * 杩炴帴鎴愬姛璋冪敤
+ * 璇ヨ繛鎺ユ垚鍔熻〃绀哄畬鍏ㄨ繛鎺ユ垚鍔燂紝瀵逛簬TCP鑰岃█灏辨槸涓夋鎻℃墜鎴愬姛
+ * @param ctx
+ * @throws Exception
+ */
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) throws Exception {
+ // 璋冪敤璇ユ柟娉曡〃绀鸿繛鎺ユ垚鍔
+ connectSuccess();
+
+ // 杩炴帴鎴愬姛鍚庡彂閫佸績璺虫秷鎭嚦鏈嶅姟绔
+ HeartBeatMessage.write(ctx);
+
+ ctx.fireChannelActive();
+ }
+
+ /**
+ * 杩炴帴澶辫触鏃惰皟鐢
+ * 姝ゅ鏄Е鍙戦噸杩炵殑鍏ュ彛
+ * @param ctx
+ * @throws Exception
+ */
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+
+ System.err.println("Connection Exception, Close And Reconnect !!!");
+ // 璋冪敤璇ユ柟娉曟椂琛ㄧず杩炴帴鍏抽棴浜嗭紙鏃犺鏄粈涔堝師鍥狅級
+ // 杩炴帴鍏抽棴鐨勬儏鍐典笅闇瑕侀噸鏂拌繛鎺
+
+ connectFail();
+
+ ctx.close();
+
+ for (int i = 0; i < maxReconnectSize; i++) {
+ reconnectTimer.schedule(this, defaultReconnectSeconds << i, TimeUnit.SECONDS);
+ }
+
+ ctx.fireChannelInactive();
+ }
+
+ @Override
+ public void run() {
+ if (isNeedReconnect()) {
+ // 閲嶈繛
+ try {
+ reconnectLock.lock();
+ if (isNeedReconnect()) {
+
+ bootstrap.handler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(Channel ch) throws Exception {
+ ch.pipeline()
+ .addLast(frontHandlers)
+ .addLast(new IdleStateHandler(10, 4, 0, TimeUnit.SECONDS))
+ .addLast(new LineBasedFrameDecoder(1024))
+ .addLast(afterHandlers)
+ ;
+ }
+ });
+
+ channelFuture = bootstrap.connect(hostName, port);
+
+ // 澧炲姞鐩戝惉鍣ㄧ敤浜庡垽鏂湰娆¢噸杩炴槸鍚︽垚鍔
+ channelFuture.addListener((ChannelFutureListener) future -> {
+ boolean isReconnectSuccess = future.isSuccess();
+ if (isReconnectSuccess) {
+ // 杩炴帴鎴愬姛
+ connectSuccess();
+ } else {
+ connectFail();
+ }
+ });
+
+ }
+ } finally {
+ reconnectLock.unlock();
+ }
+ }
+ }
+
+ private boolean isNeedReconnect() {
+ return isWorking && !currentActive.get();
+ }
+
+ private void connectSuccess() {
+ this.currentActive.set(true);
+ }
+
+ private void connectFail() {
+ this.currentActive.set(false);
+ }
+
+ @Override
+ public void close() {
+ this.isWorking = false;
+ this.reconnectTimer.shutdown();
+ }
+
+ /**
+ * 璁剧疆璋冨害鍣
+ */
+ private void initTimer() {
+ ThreadFactory timerFactory = new ThreadFactoryBuilder()
+ .setNameFormat("reconnect-pool-%d").build();
+
+ reconnectTimer = new ScheduledThreadPoolExecutor(1, timerFactory, new ThreadPoolExecutor.AbortPolicy());
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/listener/ReplyListener.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/listener/ReplyListener.java
new file mode 100644
index 00000000..ac9221d0
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/connection/listener/ReplyListener.java
@@ -0,0 +1,87 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.connection.listener.ReplyListener
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/12 涓婂崍10:36
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.connection.listener;
+
+import com.jd.blockchain.stp.communication.callback.CallBackBarrier;
+import com.jd.blockchain.stp.communication.callback.CallBackDataListener;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+
+
+/**
+ * 搴旂瓟鐩戝惉鍣
+ * @author shaozhuguang
+ * @create 2019/4/12
+ * @since 1.0.0
+ */
+
+public class ReplyListener {
+
+ /**
+ * 鐩戝惉鐨凨ey锛岄氬父鐢ㄤ簬鎻忚堪鍞竴鐨勮姹
+ */
+ private String listenKey;
+
+ /**
+ * 娑堟伅澶勭悊绫诲瀷
+ * REMOVE锛氳〃绀哄鐞嗗畬璇ュ璞′箣鍚庝粠缂撳瓨涓竻闄
+ * HOLD锛氳〃绀哄鐞嗗畬璇ュ璞′箣鍚庝粛鍦ㄧ紦瀛樹腑淇濆瓨
+ */
+ private MANAGE_TYPE manageType = MANAGE_TYPE.REMOVE;
+
+ /**
+ * 鏁版嵁鍥炶皟鐩戝惉鍣
+ */
+ private CallBackDataListener callBackDataListener;
+
+ /**
+ * 鍥炶皟鏍呮爮
+ */
+ private CallBackBarrier callBackBarrier;
+
+ public ReplyListener(String listenKey, RemoteNode remoteNode) {
+ this(listenKey, remoteNode, null);
+ }
+
+ public ReplyListener(String listenKey, RemoteNode remoteNode, CallBackBarrier callBackBarrier) {
+ this.listenKey = listenKey;
+ this.callBackDataListener = new CallBackDataListener(remoteNode);
+ this.callBackBarrier = callBackBarrier;
+ }
+
+ public void setManageType(MANAGE_TYPE manageType) {
+ this.manageType = manageType;
+ }
+
+ public String listenKey() {
+ return listenKey;
+ }
+
+ public CallBackDataListener callBackDataListener() {
+ return this.callBackDataListener;
+ }
+
+ public void replyData(byte[] reply) {
+ // 璁剧疆鏁版嵁
+ this.callBackDataListener.setCallBackData(reply);
+ if (this.callBackBarrier != null) {
+ // 鍚屾閲婃斁瀵瑰簲鐨勬爡鏍
+ this.callBackBarrier.release();
+ }
+ }
+
+ public MANAGE_TYPE manageType() {
+ return this.manageType;
+ }
+
+ public enum MANAGE_TYPE {
+ HOLD,
+ REMOVE,
+ ;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/ConnectionManager.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/ConnectionManager.java
new file mode 100644
index 00000000..c8336284
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/ConnectionManager.java
@@ -0,0 +1,175 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.ConnectionManager
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓嬪崍6:11
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.manager;
+
+import com.jd.blockchain.stp.communication.callback.CallBackLauncher;
+import com.jd.blockchain.stp.communication.connection.Receiver;
+import com.jd.blockchain.stp.communication.connection.Connection;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 杩炴帴绠$悊鍣
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ * @date 2019-04-18 15:11
+ */
+
+public class ConnectionManager {
+
+ /**
+ * Connection瀵瑰簲Map
+ * RemoteNode鍞竴鎬э細IP锛圚OST锛+PORT
+ */
+ private final Map connectionMap = new ConcurrentHashMap<>();
+
+ /**
+ * 杩炴帴绠$悊鍣ㄥ搴擬AP
+ * 浠ョ洃鍚鍙o紙int锛変綔涓篕ey锛岃繘琛屽敮涓鎬х害鏉
+ */
+ private static final Map connectionManagerMap = new ConcurrentHashMap<>();
+
+ /**
+ * connectionManagerMap鎺у埗閿
+ */
+ private static final Lock managerLock = new ReentrantLock();
+
+ /**
+ * connectionMap鎺у埗閿
+ */
+ private static final Lock connectionLock = new ReentrantLock();
+
+ /**
+ * 褰撳墠ConnectionManager瀵瑰簲鐨凴eceiver
+ */
+ private Receiver receiver;
+
+ /**
+ * 闈欐丆onnectionManager鏋勯犲櫒
+ *
+ * @param localNode
+ * 鏈湴鑺傜偣
+ * @return
+ * 浼樺厛杩斿洖Map涓殑瀵硅薄
+ */
+ public static final ConnectionManager newConnectionManager(LocalNode localNode) {
+ int listenPort = localNode.getPort();
+ if (!connectionManagerMap.containsKey(listenPort)) {
+ try {
+ managerLock.lock();
+ if (!connectionManagerMap.containsKey(listenPort)) {
+ ConnectionManager connectionManager = newInstance(localNode);
+ connectionManagerMap.put(listenPort, connectionManager);
+ return connectionManager;
+ }
+ } finally {
+ managerLock.unlock();
+ }
+ }
+ return connectionManagerMap.get(listenPort);
+ }
+
+ /**
+ * 鍐呴儴璋冪敤鐨勯潤鎬佹瀯閫犲櫒
+ *
+ * @param localNode
+ * 鏈湴鑺傜偣
+ * @return
+ */
+ private static final ConnectionManager newInstance(LocalNode localNode) {
+ return new ConnectionManager(new Receiver(localNode));
+ }
+
+ /**
+ * 鍚姩
+ * 璇ュ惎鍔ㄦ槸鍚姩Receiver锛岃繑鍥炲惎鍔ㄧ殑鐘舵
+ *
+ * @param messageExecutorClass
+ * 褰撳墠鑺傜偣甯屾湜鍏朵粬鑺傜偣鏀跺埌璇ヨ妭鐐逛俊鎭椂鐨勫鐞咹andler
+ * @return
+ * 鍥炶皟鎵ц鍣
+ * @throws InterruptedException
+ */
+ public final CallBackLauncher start(String messageExecutorClass) throws InterruptedException {
+ receiver.initReceiverHandler(this, messageExecutorClass);
+ receiver.startListen();
+ // 鍒ゆ柇鏄惁鍚姩瀹屾垚锛屽惎鍔ㄥ畬鎴愬悗鍐嶈繑鍥
+ return receiver.waitBooted();
+ }
+
+ private ConnectionManager(Receiver receiver) {
+ this.receiver = receiver;
+ }
+
+ /**
+ * 杩炴帴杩滅鑺傜偣
+ *
+ * @param remoteNode
+ * 杩滅鑺傜偣淇℃伅
+ * @param messageExecutorClass
+ * 甯屾湜杩滅鑺傜偣鎺ユ敹鍒版湰鑺傜偣娑堟伅鏃剁殑澶勭悊Handler
+ * @return
+ */
+ public Connection connect(RemoteNode remoteNode, String messageExecutorClass) {
+ if (!connectionMap.containsKey(remoteNode)) {
+ try {
+ connectionLock.lock();
+ if (!connectionMap.containsKey(remoteNode)) {
+ Connection connection = init(remoteNode, messageExecutorClass);
+ if (connection != null) {
+ // 淇濊瘉閮芥槸杩炴帴鎴愬姛鐨
+ connectionMap.put(remoteNode, connection);
+ return connection;
+ } else {
+ // 杩炴帴澶辫触杩斿洖null
+ return null;
+ }
+ }
+ } finally {
+ connectionLock.unlock();
+ }
+ }
+ return connectionMap.get(remoteNode);
+ }
+
+ /**
+ * 鍏抽棴Receiver
+ *
+ */
+ public void closeReceiver() {
+ this.receiver.close();
+ }
+
+ private Connection init(RemoteNode remoteNode, String messageExecutorClass) {
+
+ // 鍒濆鍖朇onnection
+ Connection remoteConnection = new Connection(this.receiver);
+
+ try {
+ // 杩炴帴杩滅锛岄渶瑕佸彂閫佸綋鍓嶈妭鐐瑰鐞嗙殑MessageExecuteClass
+ CallBackLauncher callBackLauncher = remoteConnection.connect(remoteNode, messageExecutorClass);
+ if (!callBackLauncher.isBootSuccess()) {
+ // TODO 鎵撳嵃閿欒鏃ュ織
+ callBackLauncher.exception().printStackTrace();
+ return null;
+ }
+ return remoteConnection;
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/RemoteSessionManager.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/RemoteSessionManager.java
new file mode 100644
index 00000000..1086fb33
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/manager/RemoteSessionManager.java
@@ -0,0 +1,180 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.RemoteSessionManager
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍11:22
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.manager;
+
+
+import com.jd.blockchain.stp.communication.MessageExecutor;
+import com.jd.blockchain.stp.communication.RemoteSession;
+import com.jd.blockchain.stp.communication.callback.CallBackLauncher;
+import com.jd.blockchain.stp.communication.connection.Connection;
+import com.jd.blockchain.stp.communication.node.LocalNode;
+import com.jd.blockchain.stp.communication.node.RemoteNode;
+import org.apache.commons.codec.binary.Hex;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+
+/**
+ * 杩滅Session绠$悊鍣
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+
+public class RemoteSessionManager {
+
+ /**
+ * 鍙洃鍚殑鏈澶х鍙
+ */
+ private static final int MAX_PORT = 65535;
+
+ /**
+ * 鑺傜偣Session鐨勯泦鍚堜俊鎭
+ */
+ private Map nodeRemoteSessionMap = new ConcurrentHashMap<>();
+
+ /**
+ * nodeRemoteSessionMap鐨勬帶鍒堕攣
+ */
+ private Lock lock = new ReentrantLock();
+
+ /**
+ * 杩炴帴绠$悊鍣
+ * 鐢ㄤ簬绠$悊搴曞眰鐨勯氫俊杩炴帴
+ */
+ private ConnectionManager connectionManager;
+
+ /**
+ * 鏈湴鑺傜偣淇℃伅
+ */
+ private LocalNode localNode;
+
+ /**
+ * 鏈湴鑺傜偣ID
+ */
+ private String localId;
+
+ /**
+ * 鏋勯犲櫒
+ * @param localNode
+ * 鏈湴鑺傜偣淇℃伅
+ */
+ public RemoteSessionManager(LocalNode localNode) {
+ this.localNode = localNode;
+ this.localId = localId();
+ // 鏍¢獙鏈湴鑺傜偣鐨勯厤缃紝闃叉寮傚父
+ check();
+ this.connectionManager = ConnectionManager.newConnectionManager(this.localNode);
+ try {
+ CallBackLauncher callBackLauncher = start();
+ if (!callBackLauncher.isBootSuccess()) {
+ // 鍚姩褰撳墠绔彛杩炴帴蹇呴』瑕佹垚鍔燂紝鍚﹀垯鍒欓鍑猴紝浜ょ敱搴旂敤绋嬪簭澶勭悊
+ throw new RuntimeException(callBackLauncher.exception());
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * RemoteSession瀵硅薄鐢熸垚鍣
+ * @param remoteNode
+ * 杩滅鑺傜偣淇℃伅
+ * @return
+ */
+ public RemoteSession newSession(RemoteNode remoteNode) {
+
+ RemoteSession remoteSession = nodeRemoteSessionMap.get(remoteNode);
+
+ if (remoteSession != null) {
+ return remoteSession;
+ } else {
+ try {
+ lock.lock();
+
+ // Double Check !!!
+ if (!nodeRemoteSessionMap.containsKey(remoteNode)) {
+ Connection remoteConnection = this.connectionManager.connect(remoteNode, localNode.messageExecutorClass());
+
+ if (remoteConnection == null) {
+ return null;
+ }
+
+ remoteSession = new RemoteSession(localId, remoteConnection);
+
+ remoteSession.init();
+
+ nodeRemoteSessionMap.put(remoteNode, remoteSession);
+
+ return remoteSession;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ return null;
+ }
+
+ public RemoteSession[] newSessions(RemoteNode[] remoteNodes) {
+ List remoteSessionList = new ArrayList<>();
+
+ for (int i = 0; i < remoteNodes.length; i++) {
+ RemoteSession remoteSession = newSession(remoteNodes[i]);
+ if (remoteSession != null) {
+ remoteSessionList.add(remoteSession);
+ }
+ }
+
+ if (remoteSessionList.isEmpty()) {
+ return null;
+ }
+
+ RemoteSession[] remoteSessions = new RemoteSession[remoteSessionList.size()];
+
+ return remoteSessionList.toArray(remoteSessions);
+ }
+
+ /**
+ * 杩斿洖搴曞眰閫氫俊绠$悊鍣
+ *
+ * @return
+ */
+ public ConnectionManager connectionManager() {
+ return this.connectionManager;
+ }
+
+ private void check() {
+ // 瑕佹眰绔彛鑼冨洿锛1~65535锛宮essageExecuteClass涓嶈兘涓簄ull
+ int listenPort = this.localNode.getPort();
+ if (listenPort <= 0 || listenPort > MAX_PORT) {
+ throw new IllegalArgumentException("Illegal Local Listen Port, Please Check !!!");
+ }
+
+ // 榛樿澶勭悊鍣ㄥ繀椤诲寘鍚紝鍙笉鍖呭惈鏈満闇瑕佸绔煡鏅撶殑澶勭悊鍣
+ MessageExecutor defaultMessageExecutor = this.localNode.defaultMessageExecutor();
+ if (defaultMessageExecutor == null) {
+ throw new IllegalArgumentException("Illegal Default MessageExecutor, Please Check !!!");
+ }
+ }
+
+ private CallBackLauncher start() throws InterruptedException {
+ return this.connectionManager.start(this.localNode.messageExecutorClass());
+ }
+
+ private String localId() {
+ return Hex.encodeHexString(localNode.toString().getBytes());
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/AbstractMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/AbstractMessage.java
new file mode 100644
index 00000000..a20ef623
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/AbstractMessage.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.AbstractMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/17 涓嬪崍4:00
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+
+/**
+ * 鎶借薄娑堟伅
+ * @author shaozhuguang
+ * @create 2019/4/17
+ * @since 1.0.0
+ */
+
+public abstract class AbstractMessage implements IMessage {
+
+ @Override
+ public ByteBuf toTransferByteBuf() {
+ byte[] message = (toTransfer() + "\r\n").getBytes();
+ ByteBuf byteBuf = Unpooled.buffer(message.length);
+ byteBuf.writeBytes(message);
+ return byteBuf;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/HeartBeatMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/HeartBeatMessage.java
new file mode 100644
index 00000000..eba5e4b6
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/HeartBeatMessage.java
@@ -0,0 +1,76 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.HeartBeatMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/12 涓嬪崍4:55
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.CharsetUtil;
+
+/**
+ * 蹇冭烦娑堟伅
+ * @author shaozhuguang
+ * @create 2019/4/12
+ * @since 1.0.0
+ */
+
+public class HeartBeatMessage implements IMessage {
+
+ /**
+ * 缁熶竴鐨勫績璺充俊鎭瓧绗︿覆
+ */
+ private static final String HEARTBEAT_STRING = "JDChainHeartBeat";
+
+ /**
+ * 缁熶竴鐨勫績璺虫秷鎭瓧绗︿覆瀵逛竴涓殑ByteBuf
+ */
+ private static final ByteBuf HEARTBEAT_MESSAGE = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer(HEARTBEAT_STRING + "\r\n",
+ CharsetUtil.UTF_8));
+
+ /**
+ * 灏嗗績璺虫秷鎭啓鍏tx
+ * @param ctx
+ */
+ public static final void write(ChannelHandlerContext ctx) {
+ ctx.writeAndFlush(HEARTBEAT_MESSAGE.duplicate());
+ }
+
+ /**
+ * 鍒ゆ柇鎺ユ敹鐨勬秷鎭槸鍚︿负蹇冭烦娑堟伅
+ *
+ * @param msg
+ * @return
+ */
+ public static final boolean isHeartBeat(Object msg) {
+ return isHeartBeat(msg.toString());
+ }
+
+ /**
+ * 鍒ゆ柇鎺ユ敹鐨勬秷鎭槸鍚︿负蹇冭烦娑堟伅
+ *
+ * @param msg
+ * @return
+ */
+ public static final boolean isHeartBeat(String msg) {
+ if (HEARTBEAT_STRING.equals(msg)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toTransfer() {
+ return HEARTBEAT_STRING;
+ }
+
+ @Override
+ public ByteBuf toTransferByteBuf() {
+ return HEARTBEAT_MESSAGE;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/IMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/IMessage.java
new file mode 100644
index 00000000..c43e8d84
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/IMessage.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.IMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/16 涓嬪崍1:58
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+import io.netty.buffer.ByteBuf;
+
+/**
+ * 娑堟伅鎺ュ彛
+ * @author shaozhuguang
+ * @create 2019/4/16
+ * @since 1.0.0
+ */
+
+public interface IMessage {
+
+ /**
+ * 娑堟伅杞崲涓哄瓧绗︿覆
+ * @return
+ */
+ String toTransfer();
+
+ /**
+ * 娑堟伅杞崲涓築yteBuf
+ * @return
+ */
+ ByteBuf toTransferByteBuf();
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/LoadMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/LoadMessage.java
new file mode 100644
index 00000000..b8971293
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/LoadMessage.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.LoadMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍10:59
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+/**
+ * 璐熻浇娑堟伅
+ * 璇ユ帴鍙g敤浜庡簲鐢ㄥ疄鐜
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+
+public interface LoadMessage {
+
+ /**
+ * 灏嗚礋杞芥秷鎭浆鎹负瀛楄妭鏁扮粍
+ * @return
+ */
+ byte[] toBytes();
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/SessionMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/SessionMessage.java
new file mode 100644
index 00000000..b3ce460b
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/SessionMessage.java
@@ -0,0 +1,112 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.SessionMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/16 涓婂崍10:40
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+import org.apache.commons.codec.binary.Hex;
+
+/**
+ * Session娑堟伅
+ * 璇ユ秷鎭敤浜庡彂閫佽嚦杩滅鑺傜偣锛屽憡璇夎繙绔妭鐐规湰鍦扮殑淇℃伅
+ * @author shaozhuguang
+ * @create 2019/4/16
+ * @since 1.0.0
+ */
+
+public class SessionMessage extends AbstractMessage implements IMessage {
+
+ /**
+ * 鏈湴鑺傜偣HOST
+ */
+ private String localHost;
+
+ /**
+ * 鏈湴鑺傜偣鐩戝惉绔彛
+ */
+ private int listenPort;
+
+ /**
+ * 杩滅鎺ユ敹鍒版湰鍦拌妭鐐逛俊鎭椂澶勭悊鐨凜lass
+ */
+ private String messageExecutor;
+
+ public SessionMessage() {
+ }
+
+ public SessionMessage(String localHost, int listenPort, String messageExecutor) {
+ this.localHost = localHost;
+ this.listenPort = listenPort;
+ this.messageExecutor = messageExecutor;
+ }
+
+ public String getLocalHost() {
+ return localHost;
+ }
+
+ public void setLocalHost(String localHost) {
+ this.localHost = localHost;
+ }
+
+ public void setListenPort(int listenPort) {
+ this.listenPort = listenPort;
+ }
+
+
+ public int getListenPort() {
+ return listenPort;
+ }
+
+ public String getMessageExecutor() {
+ return messageExecutor;
+ }
+
+ public void setMessageExecutor(String messageExecutor) {
+ this.messageExecutor = messageExecutor;
+ }
+
+ public String sessionId() {
+ return Hex.encodeHexString((this.localHost + ":" + this.listenPort).getBytes());
+ }
+
+ /**
+ * 灏嗗璞★紙鎴栬呰鎺ユ敹鍒扮殑娑堟伅锛夎浆鎹负SessionMessage
+ * @param msg
+ * 鎺ユ敹鍒扮殑娑堟伅瀵硅薄
+ * @return
+ * 鍙纭В鏋愬垯杩斿洖锛屽惁鍒欒繑鍥濶ULL
+ */
+ public static SessionMessage toSessionMessage(Object msg) {
+ String msgString = msg.toString();
+ try {
+ String[] msgArray = msgString.split("\\|");
+ if (msgArray.length == 2 || msgArray.length == 3) {
+ String host = msgArray[0];
+ int port = Integer.parseInt(msgArray[1]);
+ String msgExecutorClass = null;
+ if (msgArray.length == 3) {
+ msgExecutorClass = msgArray[2];
+ }
+ return new SessionMessage(host, port, msgExecutorClass);
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String toTransfer() {
+ // 涓哄尯鍒簬TransferMessage鐨凧SON鏍煎紡锛岃澶勪娇鐢ㄥ瓧绗︿覆杩炴帴澶勭悊
+ // 鏍煎紡锛歭ocalHost|port|class
+ if (this.messageExecutor == null) {
+ return this.localHost + "|" + this.listenPort;
+ } else {
+ return this.localHost + "|" + this.listenPort + "|" + this.messageExecutor;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/TransferMessage.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/TransferMessage.java
new file mode 100644
index 00000000..fb918295
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/message/TransferMessage.java
@@ -0,0 +1,182 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.message.TransferMessage
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓婂崍11:00
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.message;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * 搴曞眰浼犺緭鍗忚
+ *
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ */
+
+public class TransferMessage extends AbstractMessage implements IMessage{
+
+ /**
+ * sessionId锛堟弿杩拌妭鐐逛俊鎭級
+ */
+ private String sessionId;
+
+ /**
+ * 鏈娑堟伅鐨勭被鍨
+ * 0锛氳姹傦紱
+ * 1锛氬簲绛旓紱
+ */
+ private int type;
+
+ /**
+ * 娑堟伅鐨凨ey
+ */
+ private String key;
+
+ /**
+ * 娑堟伅杞戒綋鐨勫唴瀹
+ * 鏈唴瀹逛笉鍙搴忓垪鍖
+ */
+ private transient byte[] load;
+
+ /**
+ * 娑堟伅杞戒綋鐨勫唴瀹->Base64杞崲
+ */
+ private String loadBase64;
+
+ public TransferMessage() {
+ }
+
+ public TransferMessage(String sessionId, int type, String key, byte[] load) {
+ this.sessionId = sessionId;
+ this.type = type;
+ this.key = key;
+ this.load = load;
+ }
+
+ /**
+ * 杞崲涓篢ransferMessage瀵硅薄
+ *
+ * @param msg
+ * @return
+ */
+ public static TransferMessage toTransferMessage(Object msg) {
+ if (msg == null) {
+ return null;
+ }
+ TransferMessage tm;
+ try {
+ tm = JSON.parseObject(msg.toString(), TransferMessage.class);
+ tm.initLoad();
+ } catch (Exception e) {
+ return null;
+ }
+ return tm;
+ }
+
+ public byte[] load() {
+ return load;
+ }
+
+ public void initLoad() {
+ if (loadBase64 != null && loadBase64.length() > 0) {
+ load = Base64.decodeBase64(loadBase64);
+ }
+ }
+
+ public void initLoadBase64() {
+ if (load != null && load.length > 0) {
+ loadBase64 = Base64.encodeBase64String(load);
+ }
+ }
+
+ @Override
+ public String toTransfer() {
+ // 浣跨敤JSON鐨勬柟寮忓彂閫
+ // 鍒濆鍖杔oad鐨刡ase64杞崲
+ initLoadBase64();
+
+ // 灏嗗瓧绗︿覆杞崲涓篔SON
+ return JSON.toJSONString(this);
+ }
+
+ /**
+ * 杞崲涓虹洃鍚殑Key
+ * 璇ey鍙弿杩颁负浠庤繙绔彂閫佹潵娑堟伅鍙婂叾鍐呭鐨勫敮涓鎬
+ *
+ * @return
+ */
+ public String toListenKey() {
+ return key;
+ }
+
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ public void setSessionId(String sessionId) {
+ this.sessionId = sessionId;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public String loadKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getLoadBase64() {
+ return loadBase64;
+ }
+
+ public void setLoadBase64(String loadBase64) {
+ this.loadBase64 = loadBase64;
+ }
+
+ public enum MESSAGE_TYPE {
+
+ TYPE_REQUEST(0),
+
+ TYPE_RESPONSE(1);
+
+ private int code;
+
+ MESSAGE_TYPE(int code) {
+ this.code = code;
+ }
+
+ public int code() {
+ return code;
+ }
+
+ public static MESSAGE_TYPE valueOf(int code) {
+ switch (code) {
+ case 0:
+ return TYPE_REQUEST;
+ case 1:
+ return TYPE_RESPONSE;
+
+ }
+ return null;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/LocalNode.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/LocalNode.java
new file mode 100644
index 00000000..60b9b11b
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/LocalNode.java
@@ -0,0 +1,88 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.node.LocalNode
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/16 涓嬪崍3:12
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.node;
+
+import com.jd.blockchain.stp.communication.MessageExecutor;
+
+/**
+ * 鏈湴鑺傜偣
+ * @author shaozhuguang
+ * @create 2019/4/16
+ * @since 1.0.0
+ * @date 2019-04-19 09:28
+ */
+
+public class LocalNode extends RemoteNode {
+
+ /**
+ * 褰撳墠鑺傜偣娑堟伅澶勭悊鍣
+ * 璇ユ秷鎭鐞嗗櫒鐢ㄤ簬鎻忚堪杩滅鑺傜偣鏀跺埌褰撳墠鑺傜偣鐨勬秷鎭濡備綍澶勭悊
+ * 閫氬父璇ユ秷鎭鐞嗗櫒浼氫互瀛楃涓茬殑褰㈠紡鍙戦佽嚦杩滅鑺傜偣
+ */
+ private Class> messageExecutorClass;
+
+ /**
+ * 褰撳墠鑺傜偣鎺ユ敹娑堟伅榛樿澶勭悊鍣
+ * 涓巑essageExecutor涓嶅悓锛岃瀛楁鎻忚堪鐨勬槸褰撳墠鑺傜偣鎺ユ敹鍒板叾浠栬妭鐐逛俊鎭椂鐨勯粯璁ゅ鐞嗗櫒
+ * 璇ュ弬鏁扮‖鎬ц姹傚繀椤讳笉鑳戒负绌
+ */
+ private MessageExecutor defaultMessageExecutor;
+
+ /**
+ * 鏋勯犲櫒
+ * @param hostName
+ * 褰撳墠鑺傜偣Host锛岃Host蹇呴』鏄竴绉嶈繙绔妭鐐瑰彲璁块棶鐨勫舰寮
+ * @param port
+ * 褰撳墠鑺傜偣鐩戝惉绔彛
+ * @param defaultMessageExecutor
+ * 褰撳墠鑺傜偣鎺ユ敹鍒拌繙绔秷鎭棤娉曞鐞嗘椂鐨勬秷鎭鐞嗗櫒
+ *
+ */
+ public LocalNode(String hostName, int port, MessageExecutor defaultMessageExecutor) {
+ this(hostName, port, null, defaultMessageExecutor);
+ }
+
+ /**
+ * 鏋勯犲櫒
+ * @param hostName
+ * 褰撳墠鑺傜偣Host锛岃Host蹇呴』鏄竴绉嶈繙绔妭鐐瑰彲璁块棶鐨勫舰寮
+ * @param port
+ * 褰撳墠鑺傜偣鐩戝惉绔彛
+ * @param messageExecutorClass
+ * 褰撳墠鑺傜偣鏈熸湜杩滅鑺傜偣鎺ユ敹鍒版秷鎭悗鐨勫鐞嗗櫒
+ * @param defaultMessageExecutor
+ * 褰撳墠鑺傜偣鎺ユ敹鍒拌繙绔秷鎭棤娉曞鐞嗘椂鐨勬秷鎭鐞嗗櫒
+ *
+ */
+ public LocalNode(String hostName, int port, Class> messageExecutorClass, MessageExecutor defaultMessageExecutor) {
+ super(hostName, port);
+ this.messageExecutorClass = messageExecutorClass;
+ this.defaultMessageExecutor = defaultMessageExecutor;
+ }
+
+ /**
+ * 杩斿洖娑堟伅鎵ц鍣ㄧ殑绫诲搴旂殑瀛楃涓
+ * 璇ヨ繑鍥炲奸氬父鐢ㄤ簬娑堟伅浼犻
+ * @return
+ */
+ public String messageExecutorClass() {
+ if (this.messageExecutorClass == null) {
+ return null;
+ }
+ return this.messageExecutorClass.getName();
+ }
+
+ /**
+ * 杩斿洖榛樿鐨勬秷鎭鐞嗗櫒
+ * @return
+ */
+ public MessageExecutor defaultMessageExecutor() {
+ return this.defaultMessageExecutor;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/RemoteNode.java b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/RemoteNode.java
new file mode 100644
index 00000000..89287380
--- /dev/null
+++ b/source/stp/stp-communication/src/main/java/com/jd/blockchain/stp/communication/node/RemoteNode.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.stp.communication.RemoteNode
+ * Author: shaozhuguang
+ * Department: Jingdong Digits Technology
+ * Date: 2019/4/11 涓嬪崍3:40
+ * Description:
+ */
+package com.jd.blockchain.stp.communication.node;
+
+/**
+ * 鑺傜偣淇℃伅
+ * @author shaozhuguang
+ * @create 2019/4/11
+ * @since 1.0.0
+ * @date 2019-04-19 09:28
+ */
+
+public class RemoteNode {
+
+ /**
+ * 鐩戝惉绔彛
+ */
+ private int port;
+
+ /**
+ * 褰撳墠鑺傜偣鍩熷悕
+ */
+ private String hostName;
+
+ public RemoteNode(String hostName, int port) {
+ this.port = port;
+ this.hostName = hostName;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ public void setHostName(String hostName) {
+ this.hostName = hostName;
+ }
+
+ /**
+ * 閫氳繃hostName+port褰㈠紡浣滀负鍒ゆ柇鑺傜偣鐨勫敮涓鏍囪瘑
+ * @return
+ */
+ @Override
+ public int hashCode() {
+ return (hostName + ":" + port).hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj instanceof RemoteNode) {
+ RemoteNode other = (RemoteNode) obj;
+ if (this.hashCode() == other.hashCode()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return this.hostName + ":" + this.port;
+ }
+}
\ No newline at end of file
diff --git a/source/stp/stp-communication/src/test/java/com/jd/blockchain/SessionMessageTest.java b/source/stp/stp-communication/src/test/java/com/jd/blockchain/SessionMessageTest.java
new file mode 100644
index 00000000..b3cee4ab
--- /dev/null
+++ b/source/stp/stp-communication/src/test/java/com/jd/blockchain/SessionMessageTest.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright: Copyright 2016-2020 JD.COM All Right Reserved
+ * FileName: com.jd.blockchain.SessionMessageTest
+ * Author: shaozhuguang
+ * Department: Y浜嬩笟閮
+ * Date: 2019/4/17 涓嬪崍3:24
+ * Description:
+ */
+package com.jd.blockchain;
+
+import com.jd.blockchain.stp.communication.message.SessionMessage;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author shaozhuguang
+ * @create 2019/4/17
+ * @since 1.0.0
+ */
+
+public class SessionMessageTest {
+
+
+ @Test
+ public void test() {
+ SessionMessage message = new SessionMessage("127.0.0.1", 9001, "com.jd.blockchain.StpTest.StpMessageExecute");
+
+ String transMsg = message.toTransfer();
+ System.out.println(transMsg);
+
+ SessionMessage sm = SessionMessage.toSessionMessage(transMsg);
+
+ assertEquals(transMsg, sm.toTransfer());
+ }
+}
\ No newline at end of file
diff --git a/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java
new file mode 100644
index 00000000..5ae1a856
--- /dev/null
+++ b/source/utils/utils-common/src/main/java/com/jd/blockchain/utils/StringUtils.java
@@ -0,0 +1,24 @@
+package com.jd.blockchain.utils;
+
+import java.util.regex.Pattern;
+
+/**
+ * @Author zhaogw
+ * date 2018/11/26 20:46
+ */
+public class StringUtils {
+ public static boolean isEmpty(Object str) {
+ return str == null || "".equals(str);
+ }
+
+ /*
+ * 鍒ゆ柇鏄惁涓烘暣鏁
+ * @param str 浼犲叆鐨勫瓧绗︿覆
+ * @return 鏄暣鏁拌繑鍥瀟rue,鍚﹀垯杩斿洖false
+ */
+
+ public static boolean isNumber(String str) {
+ Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
+ return pattern.matcher(str).matches();
+ }
+}
\ No newline at end of file