diff --git a/source/base/src/main/resources/log4j2.xml b/source/base/src/main/resources/log4j2.xml new file mode 100644 index 00000000..26f090d7 --- /dev/null +++ b/source/base/src/main/resources/log4j2.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/binary-proto/pom.xml b/source/binary-proto/pom.xml index 37f10ea4..b0c94608 100644 --- a/source/binary-proto/pom.xml +++ b/source/binary-proto/pom.xml @@ -15,5 +15,9 @@ utils-common ${project.version} + + junit + junit + \ No newline at end of file diff --git a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java index 162ff130..f54e5331 100644 --- a/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java +++ b/source/consensus/consensus-bftsmart/src/main/java/com/jd/blockchain/consensus/bftsmart/service/BftsmartNodeServer.java @@ -6,6 +6,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import bftsmart.tom.*; +import com.jd.blockchain.utils.serialize.binary.BinarySerializeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jd.blockchain.consensus.ConsensusManageService; @@ -49,12 +50,12 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer private BftsmartConsensusManageService manageService; - private volatile BftsmartTopology topology; private volatile BftsmartConsensusSettings setting; private TOMConfiguration tomConfig; + private TOMConfiguration outerTomConfig; private HostsConfig hostsConfig; private Properties systemConfig; @@ -123,14 +124,11 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer return; } - protected void initConfig(int id, String systemConfig, String hostsConfig) { - - this.tomConfig = new TOMConfiguration(id, systemConfig, hostsConfig); - - } - protected void initConfig(int id, Properties systemsConfig, HostsConfig hostConfig) { + byte[] serialHostConf = BinarySerializeUtils.serialize(hostConfig); + Properties sysConfClone = (Properties)systemsConfig.clone(); this.tomConfig = new TOMConfiguration(id, systemsConfig, hostConfig); + this.outerTomConfig = new TOMConfiguration(id, sysConfClone, BinarySerializeUtils.deserialize(serialHostConf)); } @Override @@ -149,7 +147,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer } public TOMConfiguration getTomConfig() { - return tomConfig; + return outerTomConfig; } public int getId() { @@ -161,7 +159,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer throw new IllegalArgumentException("ReplicaID is negative!"); } this.tomConfig.setProcessId(id); - + this.outerTomConfig.setProcessId(id); } public BftsmartConsensusSettings getConsensusSetting() { @@ -243,6 +241,7 @@ public class BftsmartNodeServer extends DefaultRecoverable implements NodeServer messageHandle.commitBatch(realmName, batchId); } catch (Exception e) { // todo 需要处理应答码 404 + LOGGER.error("Error occurred while processing ordered messages! --" + e.getMessage(), e); messageHandle.rollbackBatch(realmName, batchId, TransactionState.CONSENSUS_ERROR.CODE); } diff --git a/source/contract/contract-maven-plugin/pom.xml b/source/contract/contract-maven-plugin/pom.xml index 6413f58a..d8ec237f 100644 --- a/source/contract/contract-maven-plugin/pom.xml +++ b/source/contract/contract-maven-plugin/pom.xml @@ -87,6 +87,13 @@ 3.6.0 provided + + + org.apache.maven.shared + maven-invoker + 3.0.1 + + @@ -110,31 +117,6 @@ false - - - - - - - - - - - - - - - - - - - - - - - - org.apache.maven.plugins maven-surefire-plugin @@ -142,29 +124,6 @@ true - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - - - - - - - - - - - - diff --git a/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java new file mode 100644 index 00000000..a47e4eb6 --- /dev/null +++ b/source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java @@ -0,0 +1,221 @@ +package com.jd.blockchain; + +import com.jd.blockchain.utils.ConsoleUtils; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.PluginExecution; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; +import org.apache.maven.shared.invoker.*; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +@Mojo(name = "contractCheck") +public class ContractCheckMojo extends AbstractMojo { + Logger logger = LoggerFactory.getLogger(ContractCheckMojo.class); + + @Parameter(defaultValue = "${project}", required = true, readonly = true) + private MavenProject project; + + /** + * jar's name; + */ + @Parameter + private String finalName; + + + /** + * mainClass; + */ + @Parameter + private String mainClass; + /** + * ledgerVersion; + */ + @Parameter + private String ledgerVersion; + + /** + * mvnHome; + */ + @Parameter + private String mvnHome; + + /** + * first compile the class, then parse it; + */ + @Override + public void execute() { + this.compileFiles(); + + } + + private void compileFiles(){ + // 获取当前项目pom.xml文件所在路径 +// URL targetClasses = this.getClass().getClassLoader().getResource(""); +// File file = new File(targetClasses.getPath()); +// String pomXmlPath = file.getParentFile().getParent() + File.separator + "pom.xml"; + + FileInputStream fis = null; + try { +// fis = new FileInputStream(new File(pomXmlPath)); + fis = new FileInputStream(project.getFile()); + MavenXpp3Reader reader = new MavenXpp3Reader(); + Model model = reader.read(fis); + + //delete this plugin(contractCheck) from destination pom.xml;then add the proper plugins; + Plugin plugin = model.getBuild().getPluginsAsMap().get("com.jd.blockchain:contract-maven-plugin"); + if(plugin == null){ + plugin = model.getBuild().getPluginsAsMap().get("org.apache.maven.plugins:contract-maven-plugin"); + } + + if(plugin == null) { + return; + } + + model.getBuild().removePlugin(plugin); +// model.getBuild().setPlugins(null); + +// ConsoleUtils.info("----- 不携带Plugin -----"); +// print(model); + + List plugins = new ArrayList<>(); + plugins.add(createAssembly()); + plugins.add(createCheckImports()); + + model.getBuild().setPlugins(plugins); + + ConsoleUtils.info("----- add Plugin -----"); + handle(model); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void invokeCompile(File file) { + InvocationRequest request = new DefaultInvocationRequest(); + + Invoker invoker = new DefaultInvoker(); + try { + request.setPomFile(file); + + request.setGoals( Collections.singletonList( "verify" ) ); +// request.setMavenOpts("-DmainClass="+mainClass); + invoker.setMavenHome(new File(mvnHome)); + invoker.execute(request); + } catch (MavenInvocationException e) { + e.printStackTrace(); + } + } + + private Plugin createCheckImports() { + Plugin plugin = new Plugin(); + plugin.setGroupId("com.jd.blockchain"); + plugin.setArtifactId("contract-maven-plugin"); + plugin.setVersion(ledgerVersion); + + Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); + finalNameNode.setValue(finalName); + Xpp3Dom configuration = new Xpp3Dom("configuration"); + configuration.addChild(finalNameNode); + plugin.setConfiguration(configuration); + + PluginExecution pluginExecution = new PluginExecution(); + pluginExecution.setId("make-assembly"); + pluginExecution.setPhase("verify"); + List goals = new ArrayList<>(); + goals.add("checkImports"); + pluginExecution.setGoals(goals); + List pluginExecutions = new ArrayList<>(); + pluginExecutions.add(pluginExecution); + plugin.setExecutions(pluginExecutions); + + return plugin; + } + + private Plugin createAssembly() { + Plugin plugin = new Plugin(); + plugin.setArtifactId("maven-assembly-plugin"); + + Xpp3Dom configuration = new Xpp3Dom("configuration"); + + Xpp3Dom mainClassNode = new Xpp3Dom("mainClass"); + mainClassNode.setValue(mainClass); + + Xpp3Dom manifest = new Xpp3Dom("manifest"); + manifest.addChild(mainClassNode); + + Xpp3Dom archive = new Xpp3Dom("archive"); + archive.addChild(manifest); + + Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); + finalNameNode.setValue(finalName); + + Xpp3Dom appendAssemblyId = new Xpp3Dom("appendAssemblyId"); + appendAssemblyId.setValue("false"); + + Xpp3Dom descriptorRef = new Xpp3Dom("descriptorRef"); + descriptorRef.setValue("jar-with-dependencies"); + Xpp3Dom descriptorRefs = new Xpp3Dom("descriptorRefs"); + descriptorRefs.addChild(descriptorRef); + + configuration.addChild(finalNameNode); + configuration.addChild(appendAssemblyId); + configuration.addChild(archive); + configuration.addChild(descriptorRefs); + plugin.setConfiguration(configuration); + + PluginExecution pluginExecution = new PluginExecution(); + pluginExecution.setId("make-assembly"); + pluginExecution.setPhase("package"); + List goals = new ArrayList<>(); + goals.add("single"); + pluginExecution.setGoals(goals); + List pluginExecutions = new ArrayList<>(); + pluginExecutions.add(pluginExecution); + plugin.setExecutions(pluginExecutions); + return plugin; + } + + private void handle(Model model) throws IOException { + MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer(); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + mavenXpp3Writer.write(outputStream, model); + + byte[] buffer = outputStream.toByteArray(); + + //输出文件 +// File fileOutput = new File("fileOut.xml"); +// File fileOutput = File.createTempFile("fileOut",".xml"); + File fileOutput = new File(project.getBasedir().getPath(),"fileOut.xml"); + fileOutput.createNewFile(); + + ConsoleUtils.info("fileOutput's path="+fileOutput.getPath()); + //创建文件输出流对象 + FileOutputStream fos = new FileOutputStream(fileOutput); + //将字节数组fileInput中的内容输出到文件fileOut.xml中; + ConsoleUtils.info(new String(buffer)); + fos.write(buffer); + invokeCompile(fileOutput); + fos.close(); + } +} diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml index ea7962e8..80bf8e27 100644 --- a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml +++ b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/pom.xml @@ -16,7 +16,7 @@ - contract1 + contract diff --git a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar index 7c172d0e..8e693437 100644 Binary files a/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar and b/source/contract/contract-maven-plugin/src/test/resources/project-to-test/target/contract.jar differ diff --git a/source/contract/contract-samples/pom.xml b/source/contract/contract-samples/pom.xml index cb5b4933..22b493e5 100644 --- a/source/contract/contract-samples/pom.xml +++ b/source/contract/contract-samples/pom.xml @@ -55,6 +55,16 @@ + + + org.apache.maven.plugins + maven-deploy-plugin + 2.8.2 + + true + + + diff --git a/source/crypto/crypto-impl/pom.xml b/source/crypto/crypto-impl/pom.xml deleted file mode 100644 index cb07d6c5..00000000 --- a/source/crypto/crypto-impl/pom.xml +++ /dev/null @@ -1,20 +0,0 @@ - - 4.0.0 - - com.jd.blockchain - crypto - 0.9.0-SNAPSHOT - - crypto-impl - - - - com.jd.blockchain - crypto-framework - ${project.version} - - - - \ No newline at end of file diff --git a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/AsymmtricCryptographyImpl.java b/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/AsymmtricCryptographyImpl.java deleted file mode 100644 index 41b38408..00000000 --- a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/AsymmtricCryptographyImpl.java +++ /dev/null @@ -1,220 +0,0 @@ -//package com.jd.blockchain.crypto.impl; -// -//import com.jd.blockchain.crypto.Ciphertext; -//import com.jd.blockchain.crypto.CryptoAlgorithm; -//import com.jd.blockchain.crypto.PrivKey; -//import com.jd.blockchain.crypto.PubKey; -//import com.jd.blockchain.crypto.asymmetric.*; -//import com.jd.blockchain.crypto.impl.jni.asymmetric.JNIED25519SignatureFunction; -//import com.jd.blockchain.crypto.impl.sm.asymmetric.SM2CryptoFunction; -//import com.jd.blockchain.crypto.service.classic.ED25519SignatureFunction; -// -//public class AsymmtricCryptographyImpl implements AsymmetricCryptography { -// -// private static final SignatureFunction ED25519_SIGF = new ED25519SignatureFunction(); -// -// private static final SignatureFunction SM2_SIGF = new SM2CryptoFunction(); -// -// private static final SignatureFunction JNIED25519_SIGF = new JNIED25519SignatureFunction(); -// -// private static final AsymmetricEncryptionFunction SM2_ENCF = new SM2CryptoFunction(); -// -// /** -// * 封装了非对称密码算法对应的密钥生成算法 -// */ -// @Override -// public CryptoKeyPair generateKeyPair(CryptoAlgorithm algorithm) { -// -// //判断算法是签名算法还是非对称加密算法,并根据算法生成密钥对,否则抛出异常 -// if (algorithm.isSignable() && algorithm.hasAsymmetricKey()){ -// return getSignatureFunction(algorithm).generateKeyPair(); -// } -// else if (algorithm.isEncryptable() && algorithm.hasAsymmetricKey()){ -// return getAsymmetricEncryptionFunction(algorithm).generateKeyPair(); -// } -// else throw new IllegalArgumentException("The specified algorithm is not signature or asymmetric encryption algorithm!"); -// } -// -// @Override -// public SignatureFunction getSignatureFunction(CryptoAlgorithm algorithm) { -// //遍历签名算法,如果满足,则返回实例 -// switch (algorithm) { -// case ED25519: -// return ED25519_SIGF; -// case SM2: -// return SM2_SIGF; -// case JNIED25519: -// return JNIED25519_SIGF; -// default: -// break; -// } -// throw new IllegalArgumentException("The specified algorithm is not signature algorithm!"); -// } -// -// @Override -// public boolean verify(byte[] digestBytes, byte[] pubKeyBytes, byte[] data) { -// -// //得到SignatureDigest类型的签名摘要,并得到算法标识 -// SignatureDigest signatureDigest = resolveSignatureDigest(digestBytes); -// CryptoAlgorithm algorithm = signatureDigest.getAlgorithm(); -// PubKey pubKey = resolvePubKey(pubKeyBytes); -// -// //验证两个输入中算法标识一致,否则抛出异常 -// if (algorithm != signatureDigest.getAlgorithm()) -// throw new IllegalArgumentException("Digest's algorithm and key's are not matching!"); -// -// //根据算法标识,调用对应算法实例来验证签名摘要 -// return getSignatureFunction(algorithm).verify(signatureDigest,pubKey,data); -// } -// -// @Override -// public AsymmetricEncryptionFunction getAsymmetricEncryptionFunction(CryptoAlgorithm algorithm) { -// //遍历非对称加密算法,如果满足,则返回实例 -// switch (algorithm) { -// case SM2: -// return SM2_ENCF; -// default: -// break; -// } -// throw new IllegalArgumentException("The specified algorithm is not asymmetric encryption algorithm!"); -// } -// -// @Override -// public byte[] decrypt(byte[] privKeyBytes, byte[] ciphertextBytes) { -// -// //分别得到PrivKey和Ciphertext类型的密钥和密文,以及privKey对应的算法 -// PrivKey privKey = resolvePrivKey(privKeyBytes); -// Ciphertext ciphertext = resolveCiphertext(ciphertextBytes); -// CryptoAlgorithm algorithm = privKey.getAlgorithm(); -// -// //验证两个输入中算法标识一致,否则抛出异常 -// if (algorithm != ciphertext.getAlgorithm()) -// throw new IllegalArgumentException("Ciphertext's algorithm and key's are not matching!"); -// -// //根据算法标识,调用对应算法实例来计算返回明文 -// return getAsymmetricEncryptionFunction(algorithm).decrypt(privKey,ciphertext); -// } -// -// @Override -// public Ciphertext resolveCiphertext(byte[] ciphertextBytes) { -// Ciphertext ciphertext = tryResolveCiphertext(ciphertextBytes); -// if (ciphertext == null) -// throw new IllegalArgumentException("This ciphertextBytes cannot be resolved!"); -// else return ciphertext; -// } -// -// @Override -// public Ciphertext tryResolveCiphertext(byte[] ciphertextBytes) { -// //遍历非对称加密算法,如果满足,则返回解析结果 -// if (SM2_ENCF.supportCiphertext(ciphertextBytes)){ -// return SM2_ENCF.resolveCiphertext(ciphertextBytes); -// } -// //否则返回null -// return null; -// } -// -// @Override -// public SignatureDigest resolveSignatureDigest(byte[] digestBytes) { -// SignatureDigest signatureDigest = tryResolveSignatureDigest(digestBytes); -// if (signatureDigest == null) -// throw new IllegalArgumentException("This digestBytes cannot be resolved!"); -// else return signatureDigest; -// } -// -// @Override -// public SignatureDigest tryResolveSignatureDigest(byte[] digestBytes) { -// //遍历签名算法,如果满足,则返回解析结果 -// if (ED25519_SIGF.supportDigest(digestBytes)){ -// return ED25519_SIGF.resolveDigest(digestBytes); -// } -// if (SM2_SIGF.supportDigest(digestBytes)){ -// return SM2_SIGF.resolveDigest(digestBytes); -// } -// if (JNIED25519_SIGF.supportDigest(digestBytes)){ -// return JNIED25519_SIGF.resolveDigest(digestBytes); -// } -// //否则返回null -// return null; -// } -// -// @Override -// public byte[] retrievePubKeyBytes(byte[] privKeyBytes) { -// byte[] pubKeyBytes = tryRetrievePubKeyBytes(privKeyBytes); -// if (pubKeyBytes == null) -// throw new IllegalArgumentException("The specified algorithm in privKeyBytes is not signature or asymmetric encryption algorithm!"); -// else return pubKeyBytes; -// } -// -// @Override -// public byte[] tryRetrievePubKeyBytes(byte[] privKeyBytes) { -// //解析私钥获得算法标识 -// CryptoAlgorithm algorithm = resolvePrivKey(privKeyBytes).getAlgorithm(); -// -// //判断算法是签名算法还是非对称加密算法,并根据算法生成密钥对,否则抛出异常 -// if (algorithm.isSignable() && algorithm.hasAsymmetricKey()){ -// return getSignatureFunction(algorithm).retrievePubKeyBytes(privKeyBytes); -// } -// else if (algorithm.isEncryptable() && algorithm.hasAsymmetricKey()){ -// return getAsymmetricEncryptionFunction(algorithm).retrievePubKeyBytes(privKeyBytes); -// } -// //否则返回null -// return null; -// } -// -// @Override -// public PubKey resolvePubKey(byte[] pubKeyBytes) { -// PubKey pubKey = tryResolvePubKey(pubKeyBytes); -// if (pubKey == null) -// throw new IllegalArgumentException("This pubKeyBytes cannot be resolved!"); -// else return pubKey; -// -// } -// -// @Override -// public PubKey tryResolvePubKey(byte[] pubKeyBytes) { -// //遍历签名算法,如果满足,则返回解析结果 -// if (ED25519_SIGF.supportPubKey(pubKeyBytes)){ -// return ED25519_SIGF.resolvePubKey(pubKeyBytes); -// } -// if (SM2_SIGF.supportPubKey(pubKeyBytes)){ -// return SM2_SIGF.resolvePubKey(pubKeyBytes); -// } -// if (JNIED25519_SIGF.supportPubKey(pubKeyBytes)){ -// return JNIED25519_SIGF.resolvePubKey(pubKeyBytes); -// } -// //遍历非对称加密算法,如果满足,则返回解析结果 -// if (SM2_ENCF.supportPubKey(pubKeyBytes)){ -// return SM2_ENCF.resolvePubKey(pubKeyBytes); -// } -// //否则返回null -// return null; -// } -// -// @Override -// public PrivKey resolvePrivKey(byte[] privKeyBytes) { -// PrivKey privKey = tryResolvePrivKey(privKeyBytes); -// if (privKey == null) -// throw new IllegalArgumentException("This privKeyBytes cannot be resolved!"); -// else return privKey; -// } -// -// @Override -// public PrivKey tryResolvePrivKey(byte[] privKeyBytes) { -// //遍历签名算法,如果满足,则返回解析结果 -// if (ED25519_SIGF.supportPrivKey(privKeyBytes)){ -// return ED25519_SIGF.resolvePrivKey(privKeyBytes); -// } -// if (SM2_SIGF.supportPrivKey(privKeyBytes)){ -// return SM2_SIGF.resolvePrivKey(privKeyBytes); -// } -// if (JNIED25519_SIGF.supportPrivKey(privKeyBytes)){ -// return JNIED25519_SIGF.resolvePrivKey(privKeyBytes); -// } -// //遍历非对称加密算法,如果满足,则返回解析结果 -// if (SM2_ENCF.supportPrivKey(privKeyBytes)){ -// return SM2_ENCF.resolvePrivKey(privKeyBytes); -// } -// //否则返回null -// return null; -// } -//} diff --git a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/CryptoFactoryImpl.java b/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/CryptoFactoryImpl.java deleted file mode 100644 index ffd35e66..00000000 --- a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/CryptoFactoryImpl.java +++ /dev/null @@ -1,30 +0,0 @@ -//package com.jd.blockchain.crypto.impl; -// -//import com.jd.blockchain.crypto.CryptoFactory; -//import com.jd.blockchain.crypto.asymmetric.AsymmetricCryptography; -//import com.jd.blockchain.crypto.hash.HashCryptography; -//import com.jd.blockchain.crypto.symmetric.SymmetricCryptography; -// -//public class CryptoFactoryImpl implements CryptoFactory { -// -// //Field; -// private static HashCryptography hashCryptography = new HashCryptographyImpl(); -// private static AsymmetricCryptography asymmetricCryptography = new AsymmtricCryptographyImpl(); -// private static SymmetricCryptography symmetricCryptography = new SymmetricCryptographyImpl(); -// -// @Override -// public HashCryptography hashCryptography() { -// return hashCryptography; -// } -// -// @Override -// public AsymmetricCryptography asymmetricCryptography() { -// return asymmetricCryptography; -// } -// -// @Override -// public SymmetricCryptography symmetricCryptography() { -// return symmetricCryptography; -// } -// -//} diff --git a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/HashCryptographyImpl.java b/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/HashCryptographyImpl.java deleted file mode 100644 index 59a1defc..00000000 --- a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/HashCryptographyImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -//package com.jd.blockchain.crypto.impl; -// -//import com.jd.blockchain.crypto.CryptoAlgorithm; -//import com.jd.blockchain.crypto.hash.HashCryptography; -//import com.jd.blockchain.crypto.hash.HashDigest; -//import com.jd.blockchain.crypto.hash.HashFunction; -//import com.jd.blockchain.crypto.impl.jni.hash.JNIRIPEMD160HashFunction; -//import com.jd.blockchain.crypto.impl.jni.hash.JNISHA256HashFunction; -//import com.jd.blockchain.crypto.impl.sm.hash.SM3HashFunction; -//import com.jd.blockchain.crypto.service.classic.RIPEMD160HashFunction; -//import com.jd.blockchain.crypto.service.classic.SHA256HashFunction; -// -//public class HashCryptographyImpl implements HashCryptography { -// -// private static final HashFunction SHA256_FUNC = new SHA256HashFunction(); -// private static final HashFunction RIPEMD160_FUNC = new RIPEMD160HashFunction(); -// private static final HashFunction SM3_FUNC = new SM3HashFunction(); -// -// private static final HashFunction JNISHA256_FUNC = new JNISHA256HashFunction(); -// private static final HashFunction JNIRIPEMD160_FUNC = new JNIRIPEMD160HashFunction(); -// -// @Override -// public HashFunction getFunction(CryptoAlgorithm algorithm) { -// -// // 遍历哈希算法,如果满足,则返回实例 -// switch (algorithm) { -// case SHA256: -// return SHA256_FUNC; -// case RIPEMD160: -// return RIPEMD160_FUNC; -// case SM3: -// return SM3_FUNC; -// case JNISHA256: -// return JNISHA256_FUNC; -// case JNIRIPEMD160: -// return JNIRIPEMD160_FUNC; -// default: -// break; -// } -// throw new IllegalArgumentException("The specified algorithm is not hash algorithm!"); -// } -// -// @Override -// public boolean verify(byte[] digestBytes, byte[] data) { -// HashDigest hashDigest = resolveHashDigest(digestBytes); -// return verify(hashDigest,data); -// } -// -// @Override -// public boolean verify(HashDigest digest, byte[] data) { -// CryptoAlgorithm algorithm = digest.getAlgorithm(); -// return getFunction(algorithm).verify(digest, data); -// } -// -// @Override -// public HashDigest resolveHashDigest(byte[] digestBytes) { -// HashDigest hashDigest = tryResolveHashDigest(digestBytes); -// if (hashDigest == null) -// throw new IllegalArgumentException("This digestBytes cannot be resolved!"); -// else return hashDigest; -// } -// -// @Override -// public HashDigest tryResolveHashDigest(byte[] digestBytes) { -// //遍历哈希函数,如果满足,则返回解析结果 -// if (SHA256_FUNC.supportHashDigest(digestBytes)) { -// return SHA256_FUNC.resolveHashDigest(digestBytes); -// } -// if (RIPEMD160_FUNC.supportHashDigest(digestBytes)) { -// return RIPEMD160_FUNC.resolveHashDigest(digestBytes); -// } -// if (SM3_FUNC.supportHashDigest(digestBytes)) { -// return SM3_FUNC.resolveHashDigest(digestBytes); -// } -// if (JNISHA256_FUNC.supportHashDigest(digestBytes)) { -// return JNISHA256_FUNC.resolveHashDigest(digestBytes); -// } -// if (JNIRIPEMD160_FUNC.supportHashDigest(digestBytes)) { -// return JNIRIPEMD160_FUNC.resolveHashDigest(digestBytes); -// } -// //否则返回null -// return null; -// } -//} \ No newline at end of file diff --git a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/SymmetricCryptographyImpl.java b/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/SymmetricCryptographyImpl.java deleted file mode 100644 index 115855d0..00000000 --- a/source/crypto/crypto-impl/src/main/java/com/jd/blockchain/crypto/impl/SymmetricCryptographyImpl.java +++ /dev/null @@ -1,101 +0,0 @@ -//package com.jd.blockchain.crypto.impl; -// -//import com.jd.blockchain.crypto.Ciphertext; -//import com.jd.blockchain.crypto.CryptoAlgorithm; -//import com.jd.blockchain.crypto.SingleKey; -//import com.jd.blockchain.crypto.impl.sm.symmetric.SM4SymmetricEncryptionFunction; -//import com.jd.blockchain.crypto.service.classic.AESSymmetricEncryptionFunction; -//import com.jd.blockchain.crypto.symmetric.SymmetricCryptography; -//import com.jd.blockchain.crypto.symmetric.SymmetricEncryptionFunction; -// -//public class SymmetricCryptographyImpl implements SymmetricCryptography { -// -// private static final SymmetricEncryptionFunction AES_ENCF = new AESSymmetricEncryptionFunction(); -// private static final SymmetricEncryptionFunction SM4_ENCF = new SM4SymmetricEncryptionFunction(); -// -// /** -// * 封装了对称密码算法对应的密钥生成算法 -// */ -// @Override -// public SingleKey generateKey(CryptoAlgorithm algorithm) { -// -// //验证算法标识是对称加密算法,并根据算法生成对称密钥,否则抛出异常 -// if (algorithm.isEncryptable() && algorithm.isSymmetric() ){ -// return (SingleKey) getSymmetricEncryptionFunction(algorithm).generateSymmetricKey(); -// } -// else throw new IllegalArgumentException("The specified algorithm is not symmetric encryption algorithm!"); -// } -// -// @Override -// public SymmetricEncryptionFunction getSymmetricEncryptionFunction(CryptoAlgorithm algorithm) { -// -// // 遍历对称加密算法,如果满足,则返回实例 -// switch (algorithm) { -// case AES: -// return AES_ENCF; -// case SM4: -// return SM4_ENCF; -// default: -// break; -// } -// throw new IllegalArgumentException("The specified algorithm is not symmetric encryption algorithm!"); -// } -// -// @Override -// public byte[] decrypt(byte[] symmetricKeyBytes, byte[] ciphertextBytes) { -// -// //分别得到SymmetricKey和Ciphertext类型的密钥和密文,以及symmetricKey对应的算法 -// SingleKey symmetricKey = resolveSymmetricKey(symmetricKeyBytes); -// Ciphertext ciphertext = resolveCiphertext(ciphertextBytes); -// CryptoAlgorithm algorithm = symmetricKey.getAlgorithm(); -// -// //验证两个输入中算法标识一致,否则抛出异常 -// if (algorithm != ciphertext.getAlgorithm()) -// throw new IllegalArgumentException("Ciphertext's algorithm and key's are not matching!"); -// -// //根据算法标识,调用对应算法实例来计算返回明文 -// return getSymmetricEncryptionFunction(algorithm).decrypt(symmetricKey,ciphertext); -// } -// -// @Override -// public Ciphertext resolveCiphertext(byte[] ciphertextBytes) { -// Ciphertext ciphertext = tryResolveCiphertext(ciphertextBytes); -// if (ciphertext == null) -// throw new IllegalArgumentException("This ciphertextBytes cannot be resolved!"); -// else return ciphertext; -// } -// -// @Override -// public Ciphertext tryResolveCiphertext(byte[] ciphertextBytes) { -// //遍历对称加密算法,如果满足,则返回解析结果 -// if (AES_ENCF.supportCiphertext(ciphertextBytes)) { -// return AES_ENCF.resolveCiphertext(ciphertextBytes); -// } -// if (SM4_ENCF.supportCiphertext(ciphertextBytes)) { -// return SM4_ENCF.resolveCiphertext(ciphertextBytes); -// } -// //否则返回null -// return null; -// } -// -// @Override -// public SingleKey resolveSymmetricKey(byte[] symmetricKeyBytes) { -// SingleKey symmetricKey = tryResolveSymmetricKey(symmetricKeyBytes); -// if (symmetricKey == null) -// throw new IllegalArgumentException("This symmetricKeyBytes cannot be resolved!"); -// else return symmetricKey; -// } -// -// @Override -// public SingleKey tryResolveSymmetricKey(byte[] symmetricKeyBytes) { -// //遍历对称加密算法,如果满足,则返回解析结果 -// if(AES_ENCF.supportSymmetricKey(symmetricKeyBytes)) { -// return AES_ENCF.resolveSymmetricKey(symmetricKeyBytes); -// } -// if(SM4_ENCF.supportSymmetricKey(symmetricKeyBytes)) { -// return SM4_ENCF.resolveSymmetricKey(symmetricKeyBytes); -// } -// //否则返回null -// return null; -// } -//} diff --git a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyAsymmetricEncryptionTest.java b/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyAsymmetricEncryptionTest.java deleted file mode 100644 index 87ff496f..00000000 --- a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyAsymmetricEncryptionTest.java +++ /dev/null @@ -1,55 +0,0 @@ -//package test.com.jd.blockchain.crypto.performance; -// -//import com.jd.blockchain.crypto.Ciphertext; -//import com.jd.blockchain.crypto.PrivKey; -//import com.jd.blockchain.crypto.PubKey; -//import com.jd.blockchain.crypto.asymmetric.CryptoKeyPair; -//import com.jd.blockchain.crypto.impl.sm.asymmetric.SM2CryptoFunction; -//import org.bouncycastle.util.encoders.Hex; -// -//public class MyAsymmetricEncryptionTest { -// -// public static void main(String[] args) { -// -// String string1K = "0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210"; -// String string1M = ""; -// for (int i = 0; i < 1024 ; i++) -// { -// string1M = string1M + string1K; -// } -// -// byte[] data1K = Hex.decode(string1K); -// byte[] data1M = Hex.decode(string1M); -// int count = 10000; -// -// SM2CryptoFunction sm2 = new SM2CryptoFunction(); -// CryptoKeyPair keyPairSM2 = sm2.generateKeyPair(); -// PrivKey privKeySM2 = keyPairSM2.getPrivKey(); -// PubKey pubKeySM2 = keyPairSM2.getPubKey(); -// -// System.out.println("=================== do SM2 encrypt test ==================="); -// Ciphertext ciphertextSM2 = null; -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// ciphertextSM2 = sm2.encrypt(pubKeySM2,data1K); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM2 Encrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// System.out.println("=================== do SM2 decrypt test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// sm2.decrypt(privKeySM2,ciphertextSM2); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM2 Decrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// } -//} diff --git a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyHashTest.java b/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyHashTest.java deleted file mode 100644 index dfa922fc..00000000 --- a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MyHashTest.java +++ /dev/null @@ -1,62 +0,0 @@ -//package test.com.jd.blockchain.crypto.performance; -// -//import com.jd.blockchain.crypto.impl.sm.hash.SM3HashFunction; -//import com.jd.blockchain.crypto.service.classic.RIPEMD160HashFunction; -//import com.jd.blockchain.crypto.service.classic.SHA256HashFunction; -// -//import java.util.Random; -// -//public class MyHashTest { -// -// public static void main(String[] args) { -// -// Random rand = new Random(); -// byte[] data1K = new byte[1024]; -// rand.nextBytes(data1K); -// int count = 1000000; -// -// SHA256HashFunction sha256hf = new SHA256HashFunction(); -// -// System.out.println("=================== do SHA256 hash test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// sha256hf.hash(data1K); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SHA256 hashing Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// RIPEMD160HashFunction ripemd160hf = new RIPEMD160HashFunction(); -// -// System.out.println("=================== do RIPEMD160 hash test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// ripemd160hf.hash(data1K); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("RIPEMD160 hashing Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// SM3HashFunction sm3hf = new SM3HashFunction(); -// -// System.out.println("=================== do SM3 hash test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// sm3hf.hash(data1K); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM3 hashing Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// } -//} -// diff --git a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySignatureTest.java b/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySignatureTest.java deleted file mode 100644 index 684ecdb6..00000000 --- a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySignatureTest.java +++ /dev/null @@ -1,83 +0,0 @@ -//package test.com.jd.blockchain.crypto.performance; -// -//import com.jd.blockchain.crypto.PrivKey; -//import com.jd.blockchain.crypto.PubKey; -//import com.jd.blockchain.crypto.asymmetric.CryptoKeyPair; -//import com.jd.blockchain.crypto.asymmetric.SignatureDigest; -//import com.jd.blockchain.crypto.impl.sm.asymmetric.SM2CryptoFunction; -//import com.jd.blockchain.crypto.service.classic.ED25519SignatureFunction; -// -//import java.util.Random; -// -//public class MySignatureTest { -// -// public static void main(String[] args) { -// -// Random rand = new Random(); -// byte[] data = new byte[64]; -// rand.nextBytes(data); -// int count = 10000; -// -// ED25519SignatureFunction ed25519sf = new ED25519SignatureFunction(); -// CryptoKeyPair keyPairED25519 = ed25519sf.generateKeyPair(); -// PrivKey privKeyED25519 = keyPairED25519.getPrivKey(); -// PubKey pubKeyED25519 = keyPairED25519.getPubKey(); -// -// System.out.println("=================== do ED25519 sign test ==================="); -// SignatureDigest signatureDigestED25519 = null; -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// signatureDigestED25519 = ed25519sf.sign(privKeyED25519,data); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("ED25519 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// System.out.println("=================== do ED25519 verify test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// ed25519sf.verify(signatureDigestED25519,pubKeyED25519,data); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("ED25519 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// SM2CryptoFunction sm2 = new SM2CryptoFunction(); -// CryptoKeyPair keyPairSM2 = sm2.generateKeyPair(); -// PrivKey privKeySM2 = keyPairSM2.getPrivKey(); -// PubKey pubKeySM2 = keyPairSM2.getPubKey(); -// -// -// System.out.println("=================== do SM2 sign test ==================="); -// SignatureDigest signatureDigestSM2 = null; -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// signatureDigestSM2 = sm2.sign(privKeySM2,data); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM2 Signing Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// System.out.println("=================== do SM2 verify test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// sm2.verify(signatureDigestSM2,pubKeySM2,data); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM2 Verifying Count=%s; Elapsed Times=%s; TPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// } -//} diff --git a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySymmetricEncryptionTest.java b/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySymmetricEncryptionTest.java deleted file mode 100644 index fbab4b13..00000000 --- a/source/crypto/crypto-impl/src/test/java/test/com/jd/blockchain/crypto/performance/MySymmetricEncryptionTest.java +++ /dev/null @@ -1,92 +0,0 @@ -//package test.com.jd.blockchain.crypto.performance; -// -//import com.jd.blockchain.crypto.Ciphertext; -//import com.jd.blockchain.crypto.SingleKey; -//import com.jd.blockchain.crypto.impl.sm.symmetric.SM4SymmetricEncryptionFunction; -//import com.jd.blockchain.crypto.service.classic.AESSymmetricEncryptionFunction; -// -//import org.bouncycastle.util.encoders.Hex; -// -//public class MySymmetricEncryptionTest { -// -// public static void main(String[] args) { -// -// String string1K = "0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210"; -// -//// String string1M = ""; -//// for (int i = 0; i < 1024 ; i++) -//// { -//// string1M = string1M + string1K; -//// } -// -// byte[] data1K = Hex.decode(string1K); -//// byte[] data1M = Hex.decode(string1M); -// -// int count = 100000; -// -// -// AESSymmetricEncryptionFunction aes = new AESSymmetricEncryptionFunction(); -// SingleKey keyAES = (SingleKey) aes.generateSymmetricKey(); -// Ciphertext ciphertext1KAES = null; -// Ciphertext ciphertext1MAES = null; -// -// System.out.println("=================== do AES encrypt test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// ciphertext1KAES = aes.encrypt(keyAES,data1K); -//// ciphertext1MAES = aes.encrypt(keyAES,data1M); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("AES Encrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// -// -// System.out.println("=================== do AES decrypt test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// aes.decrypt(keyAES,ciphertext1KAES); -//// aes.decrypt(keyAES,ciphertext1MAES); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("AES Decrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// SM4SymmetricEncryptionFunction sm4 = new SM4SymmetricEncryptionFunction(); -// SingleKey keySM4 = (SingleKey) sm4.generateSymmetricKey(); -// Ciphertext ciphertext1KSM4 = null; -// Ciphertext ciphertext1MSM4 = null; -// -// System.out.println("=================== do SM4 encrypt test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// ciphertext1KSM4 = sm4.encrypt(keySM4,data1K); -//// ciphertext1MSM4 =sm4.encrypt(keySM4,data1M); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM4 Encrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// -// System.out.println("=================== do SM4 decrypt test ==================="); -// for (int r = 0; r < 5; r++) { -// System.out.println("------------- round[" + r + "] --------------"); -// long startTS = System.currentTimeMillis(); -// for (int i = 0; i < count; i++) { -// sm4.decrypt(keySM4,ciphertext1KSM4); -//// sm4.decrypt(keySM4,ciphertext1MSM4); -// } -// long elapsedTS = System.currentTimeMillis() - startTS; -// System.out.println(String.format("SM4 Decrypting Count=%s; Elapsed Times=%s; KBPS=%.2f", count, elapsedTS, -// (count * 1000.00D) / elapsedTS)); -// } -// } -//} diff --git a/source/deployment/deployment-peer/src/main/resources/docs/imgs/browser.jpeg b/source/deployment/deployment-peer/src/main/resources/docs/imgs/browser.jpeg index 2cfb38a7..180367d8 100644 Binary files a/source/deployment/deployment-peer/src/main/resources/docs/imgs/browser.jpeg and b/source/deployment/deployment-peer/src/main/resources/docs/imgs/browser.jpeg differ diff --git a/source/deployment/deployment-peer/src/main/resources/docs/安装部署.MD b/source/deployment/deployment-peer/src/main/resources/docs/安装部署.MD index 28ea020d..75cd0502 100644 --- a/source/deployment/deployment-peer/src/main/resources/docs/安装部署.MD +++ b/source/deployment/deployment-peer/src/main/resources/docs/安装部署.MD @@ -1,5 +1,6 @@ # JDChain安装部署指南 +本部署指南基于JDChain1.0.0.RELEASE版本来构建。 ## 1. 部署环境 ### 1.1 系统部署结构 ![部署结构](imgs/structure.png) @@ -56,21 +57,21 @@ unzip jdchain-peer-$version.zip Peer打包程序解压完后的安装包结构如下: + bin - - keygen.sh - - ledger-init.sh - - startup.sh - - shutdown.sh + - keygen.sh + - ledger-init.sh + - startup.sh + - shutdown.sh + config - - init - + ledger-init.conf - + local.conf - + bftsmart.config(默认) - - keys - + %.priv - + %.pub - + %.pwd - - ledger-binding.conf - - application.properties + - init + + ledger.init + + local.conf + + bftsmart.config(默认) + - keys + + %.priv + + %.pub + + %.pwd + - ledger-binding.conf + - application.properties + docs + libs + system @@ -93,10 +94,10 @@ chmod 777 * Gateway节点打包程序为:jdchain-gateway-$version.tar.gz或jdchain-gateway-$version.zip,其解压完后的安装包结构如下: + bin - - startup.sh - - shutdown.sh + - startup.sh + - shutdown.sh + config - - gateway.conf + - gateway.conf + lib @@ -125,12 +126,12 @@ JDChain提供了创建用户的工具,可直接通过命令行生成一个新 **请将所有Peer节点都按照上述流程注册一个独立的用户,在实际生产环境中该过程可能由不同的参与方完成。** ### 2.3 账本初始化 -账本初始化是所有参与Peer节点进行共识,并生成初始化账本至数据库的过程。该过程需要所有节点共同参与,同时启动。 +账本初始化是所有参与Peer节点进行共识,并生成初始化账本至数据库的过程。该过程需要所有节点共同参与,**同时启动**。 #### 2.3.1 初始化配置 -*config/init* 目录下有三个配置文件需要修改:**local.conf** 、 **ledger-init.conf** 和 **bftsmart.config** 。 +*config/init* 目录下有三个配置文件需要修改:**local.conf** 、 **ledger.init** 和 **bftsmart.config** 。 + local.conf描述账本初始化的本地(即当前节点)配置; - + ledger-init.conf描述账本初始化过程中涉及到的其他参与Peer节点配置信息; + + ledger.init描述账本初始化过程中涉及到的其他参与Peer节点配置信息; + bftsmart.config为BFTSmart进行共识的相关配置。 ##### 2.3.1.1 local.conf配置 @@ -157,18 +158,11 @@ ledger.db.uri=rocksdb:///export/app/peer/rocks.db/rocksdb0.db #账本数据库的连接口令 ledger.db.pwd= - -#共识配置文件路径 -consensus.conf=../bftsmart.config - -#共识Providers配置 -#BftSmart共识Provider:com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider -consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider ``` 其中local.parti.id从 **0** 开始编号,且不同Peer节点不能相同;local.parti.privkey为当前节点私钥,即 *config/keys/%.priv* 文件中的内容;其他参数根据实际环境进行配置。 -##### 2.3.1.2 ledger-init.conf配置 +##### 2.3.1.2 ledger.init配置 ```config #账本的种子;一段16进制字符,最长可以包含64个字符;可以用字符“-”分隔,以便更容易读取; ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323ffe @@ -176,37 +170,49 @@ ledger.seed=932dfe23-fe23232f-283f32fa-dd32aa76-8322ca2f-56236cda-7136b322-cb323 #账本的描述名称;此属性不参与共识,仅仅在当前参与方的本地节点用于描述用途; #ledger.name= +#声明的账本创建时间;格式为 “yyyy-MM-dd HH:mm:ss.SSSZ”,表示”年-月-日 时:分:秒:毫秒时区“;例如:“2019-10-17 05:21:58.069+0800”,其中,+0800 表示时区是东8区 +created-time=2019-10-17 05:21:58.069+0800 + +#共识服务提供者;必须; +consensus.service-provider=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider + +#共识服务的参数配置;必须; +#consensus.conf=/export/app/peer/config/init/bftsmart.config +consensus.conf=bftsmart.config + +#密码服务提供者列表,以英文逗点“,”分隔;必须; +crypto.service-providers=com.jd.blockchain.crypto.service.classic.ClassicCryptoService, \ +com.jd.blockchain.crypto.service.sm.SMCryptoService + #参与方的个数,后续以 cons_parti.id 分别标识每一个参与方的配置; cons_parti.count=4 -#第0个参与方的名称 -cons_parti.0.name=parti-0.com -#第0个参与方的公钥文件路径 +#第0个参与方的名称; +cons_parti.0.name= +#第0个参与方的公钥文件路径; cons_parti.0.pubkey-path= -#第0个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 -cons_parti.0.pubkey=endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna -#第0个参与方的账本初始服务的主机 +#第0个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.0.pubkey= +#第0个参与方的账本初始服务的主机; cons_parti.0.initializer.host=127.0.0.1 -#第0个参与方的账本初始服务的端口 -cons_parti.0.initializer.port=17000 -#第0个参与方的账本初始服务是否开启安全连接 +#第0个参与方的账本初始服务的端口; +cons_parti.0.initializer.port=8800 +#第0个参与方的账本初始服务是否开启安全连接; cons_parti.0.initializer.secure=false - -#第1个参与方的名称 -cons_parti.1.name=parti-1.com -#第1个参与方的公钥文件路径 +#第1个参与方的名称; +cons_parti.1.name= +#第1个参与方的公钥文件路径; cons_parti.1.pubkey-path= -#第1个参与方的公钥内容(由keygen工具生成),此参数优先于 pubkey-path 参数 -cons_parti.1.pubkey=endPsK36sC5JdPCDPDAXUwZtS3sxEmqEhFcC4whayAsTTh8Z6eoZ -#第1个参与方的账本初始服务的主机 +#第1个参与方的公钥内容(由keygen工具生成);此参数优先于 pubkey-path 参数; +cons_parti.1.pubkey= +#第1个参与方的账本初始服务的主机; cons_parti.1.initializer.host=127.0.0.1 -#第1个参与方的账本初始服务的端口 -cons_parti.1.initializer.port=17010 -#第1个参与方的账本初始服务是否开启安全连接 +#第1个参与方的账本初始服务的端口; +cons_parti.1.initializer.port=8810 +#第1个参与方的账本初始服务是否开启安全连接; cons_parti.1.initializer.secure=false - ``` 账本初始化过程中,需要其他Peer节点的公钥信息进行验证及保存,因此每个节点都需要获取其他Peer节点的公钥信息至本地。配置中cons_parti.N.*****中的N需按照实际每个参与方定义的序号配置(该配置为local.conf中的local.parti.id)。其他参数根据实际环境进行配置。 @@ -214,14 +220,12 @@ cons_parti.1.initializer.secure=false ##### 2.3.1.1 bftsmart.config配置 ```config -system.block.txsize=15 - -system.block.maxdelay=500 - -system.server.0.pubkey=endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna system.server.0.network.host=127.0.0.1 system.server.0.network.port=16000 +system.server.1.network.host=127.0.0.1 +system.server.1.network.port=16010 + system.servers.num = 4 system.servers.f = 1 @@ -231,9 +235,6 @@ system.initial.view = 0,1,2,3 > 注意:上述只是将bftsmart.config文件中主要需要修改的参数显示,以方便进行相关说明,其他参数的修改可参考具体文件中的具体说明 参数具体说明如下: - + system.block.txsize:每个区块结块期望含交易数量; - + system.block.maxdelay:区块结块时最大时延(单位:毫秒),该参数与system.block.txsize符合优先发生原则; - + system.server.$n.pubkey:第n节点的公钥信息; + system.server.$n.network.host:第n个节点的域名; + system.server.$n.network.port:第n个节点的共识端口; + system.servers.num:共识节点总数; @@ -249,7 +250,7 @@ cd bin 执行命令之后,会在 *config* 目录下生成ledger-binding.conf文件,该文件即账本初始化生成的文件,Peer节点启动时需要依赖该文件。 > 1)注意:因为JDChain支持多账本形式,若config/ledger-binding.conf文件在初始化之前就存在的话,初始化操作后不会覆盖其中的内容,会以追加的方式写入。若第一次创建账本,建议先将该文件删除再进行初始化! -> 2)注意:Peer节点会定时检测ledger-binding.conf,有新账本加入时会自动进行更新,不需要重启Peer节点! +> 2)注意:Peer节点会定时检测ledger-binding.conf,有新账本加入时会自动进行更新,不需要重启Peer节点!目前默认时间为封5自动更新,即:每个小时的5/15/25/35/45/55分钟会执行; 账本初始化成功后,每个Peer节点对应的Rocksdb都会写入该账本相关的数据。 @@ -262,9 +263,9 @@ Peer节点启动依赖于 *config* 目录下ledger-binding.conf的配置,该 cd bin ./startup.sh ``` -> 1)注意:startup.sh命令中可修改启动端口,默认为:-p 17080; +> 1)注意:startup.sh命令中可修改启动端口,默认为:-p 7080; -> 2)注意:Peer节点会与账本中涉及到的参与方进行通信,当通信不成功(例如有节点尚未启动)时,会自动进行重试,因此多个Peer节点启动可不必完全同时进行。 +> 2)注意:Peer节点会与账本中涉及到的参与方进行通信,当通信不成功(例如有节点尚未启动)时,会自动进行重试,因此多个Peer节点启动可不必完全同时进行。目前默认设置为重试16次操作,每次间隔时间2秒。 ### 2.5 Gateway节点安装 GateWay(网关)节点可以认为是一个过滤节点,交易的提交及账本的查询都需要通过网关节点与Peer节点进行通信。 @@ -272,7 +273,7 @@ Gateway程序可独立部署,不需要依赖Peer节点,它的操作环境是 ```config #网关的HTTP服务地址; -http.host=127.0.0.1 +http.host=0.0.0.0 #网关的HTTP服务端口; http.port=8081 #网关的HTTP服务上下文路径,可选; @@ -292,15 +293,15 @@ peer.providers=com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider data.retrieval.url=http://192.168.151.39:10001 #默认公钥的内容(Base58编码数据); -keys.default.pubkey=endPsK36koyFr1D245Sa9j83vt6pZUdFBJoJRB3xAsWM6cwhRbna +keys.default.pubkey= #默认私钥的路径;在 pk-path 和 pk 之间必须设置其一; keys.default.privkey-path= #默认私钥的内容(加密的Base58编码数据);在 pk-path 和 pk 之间必须设置其一; -keys.default.privkey=177gjsj5PHeCpbAtJE7qnbmhuZMHAEKuMsd45zHkv8F8AWBvTBbff8yRKdCyT3kwrmAjSnY +keys.default.privkey= #默认私钥的解码密码; -keys.default.privkey-password=DYu3G8aGTMBW1WrTw76zxQJQU4DHLw9MLyy7peG4LKkY +keys.default.privkey-password= ``` -其中keys.default.%配置是网关的角色配置,目前暂不支持网关自定义角色,因此,网关可选择4个参与方的任何一个作为其配置(主要是密钥对)。 +其中keys.default.% 配置是网关的角色配置,目前暂不支持网关自定义角色,因此,网关可选择4个参与方的任何一个作为其配置(主要是密钥对)。 >注意:keys.default.privkey-password填写内容为*2.2章节*中生成的%.pwd文件中的内容! 启动网关节点只需要执行:startup.sh即可,参考命令: diff --git a/source/deployment/deployment-peer/src/main/resources/docs/安装部署.html b/source/deployment/deployment-peer/src/main/resources/docs/安装部署.html index 1d75f3c9..432e4f1e 100644 --- a/source/deployment/deployment-peer/src/main/resources/docs/安装部署.html +++ b/source/deployment/deployment-peer/src/main/resources/docs/安装部署.html @@ -1,571 +1,67 @@ - - - - - 安装部署 - - -

JDChain安装部署指南

-

1. 部署环境

-

1.1 系统部署结构

-

部署结构

-

JDChain有三类节点:Peer、网关和客户端。peer节点是区块链主节点,参与共识、账本操作等;网关节点(GateWay)与Peer节点通信,负责区块链浏览器及消息传递;客户端与网关通信,可以进行写入或查询账本等操作。

-

JDChain默认采用Rocksdb作为存储数据库,每个Peer节点与一个(或多个)Rocksdb实例连接,Rocksdb实例的数量与账本相关,不同Peer节点对应不同的Rocksdb实例。

-

JDChain也支持Redis作为其存储数据库,Redis数据库不必和Peer节点安装在同一服务器,只需要配置正确即可(后面配置会说到)。

-

JDChain默认共识机制采用的是BFTSmart,该共识算法要求最低四个共识节点,BFTSmart 对作恶节点的支持为:N = 3f+1,即在N个节点共识中可允许f个作恶节点,当节点数增加时可根据该公式进行配置。

-

本安装部署指南以四个节点为例进行说明。

+ +

JDChain安装部署指南

+

本部署指南基于JDChain1.0.0.RELEASE版本来构建。

+

1. 部署环境

+

1.1 系统部署结构

+

部署结构

+

JDChain有三类节点:Peer、网关和客户端。peer节点是区块链主节点,参与共识、账本操作等;网关节点(GateWay)与Peer节点通信,负责区块链浏览器及消息传递;客户端与网关通信,可以进行写入或查询账本等操作。

+

JDChain默认采用Rocksdb作为存储数据库,每个Peer节点与一个(或多个)Rocksdb实例连接,Rocksdb实例的数量与账本相关,不同Peer节点对应不同的Rocksdb实例。

+

JDChain也支持Redis作为其存储数据库,Redis数据库不必和Peer节点安装在同一服务器,只需要配置正确即可(后面配置会说到)。

+

JDChain默认共识机制采用的是BFTSmart,该共识算法要求最低四个共识节点,BFTSmart 对作恶节点的支持为:N = 3f+1,即在N个节点共识中可允许f个作恶节点,当节点数增加时可根据该公式进行配置。

+

本安装部署指南以四个节点为例进行说明。


-

1.2 服务器配置

-

1.2.1 硬件配置

-

为了更好的运行,JDChain推荐使用 Linux 操作系统,Peer节点自身运行对内存要求较低,但对于Rocksdb存储而言,其对运行环境有较高要求,以下为单Peer节点可正常运行 亿级交易 的参考指标:

+

1.2 服务器配置

+

1.2.1 硬件配置

+

为了更好的运行,JDChain推荐使用 Linux 操作系统,Peer节点自身运行对内存要求较低,但对于Rocksdb存储而言,其对运行环境有较高要求,以下为单Peer节点可正常运行 亿级交易 的参考指标:

-

1.2.2 软件配置

-

JDChain使用Java开发,其软件需求如下:

+

1.2.2 软件配置

+

JDChain使用Java开发,其软件需求如下:

-

注意:若数据库使用的Redis,则需要对应数据库服务器安装Redis,Redis版本要求>=3.x。

+

注意:若数据库使用的Redis,则需要对应数据库服务器安装Redis,Redis版本要求>=3.x。


-

2. 系统安装与配置

-

2.1 安装包结构

-

JDChain默认发布的安装包有两个,一个是Peer节点打包程序,一个是Gateway节点打包程序,两者默认都是用tar.gz(或zip)打包的。

-

2.1.1 Peer节点安装包

-

Peer节点打包程序为:jdchain-peer-$version.tar.gz或jdchain-peer-$version.zip,若是tar.gz压缩文件可通过tar命令解压(如下):

-
tar -xzvf jdchain-peer-$version.tar.gz
-

若是zip文件可通过unzip命令解压(如下):

-
unzip jdchain-peer-$version.zip
+

2. 系统安装与配置

+

2.1 安装包结构

+

JDChain默认发布的安装包有两个,一个是Peer节点打包程序,一个是Gateway节点打包程序,两者默认都是用tar.gz(或zip)打包的。

+

2.1.1 Peer节点安装包

+

Peer节点打包程序为:jdchain-peer-$version.tar.gz或jdchain-peer-$version.zip,若是tar.gz压缩文件可通过tar命令解压(如下):

+
tar -xzvf jdchain-peer-$version.tar.gz
+

若是zip文件可通过unzip命令解压(如下):

+
unzip jdchain-peer-$version.zip
-

注意:$version为JDChain发布的版本号

+

注意:$version为JDChain发布的版本号

-

Peer打包程序解压完后的安装包结构如下:

+

Peer打包程序解压完后的安装包结构如下:

+ +
+ \ No newline at end of file diff --git a/source/gateway/src/main/resources/log4j2.xml b/source/gateway/src/main/resources/log4j2.xml index 3fe4b122..d81fe1dc 100644 --- a/source/gateway/src/main/resources/log4j2.xml +++ b/source/gateway/src/main/resources/log4j2.xml @@ -8,7 +8,7 @@ - + diff --git a/source/ledger/ledger-core/pom.xml b/source/ledger/ledger-core/pom.xml index a4c180e5..3938916c 100644 --- a/source/ledger/ledger-core/pom.xml +++ b/source/ledger/ledger-core/pom.xml @@ -62,8 +62,13 @@ ${project.version} test + + org.mockito + mockito-core + test + - + @@ -78,42 +83,32 @@ - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java index a28a5fb5..bb57cd3c 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/AccountSet.java @@ -333,9 +333,9 @@ public class AccountSet implements Transactional, MerkleProvable { if (!updated) { return; } - String[] addresses = new String[latestAccountsCache.size()]; + Bytes[] addresses = new Bytes[latestAccountsCache.size()]; latestAccountsCache.keySet().toArray(addresses); - for (String address : addresses) { + for (Bytes address : addresses) { VersioningAccount acc = latestAccountsCache.remove(address); // cancel; if (acc.isUpdated()) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java index 799a8570..d44e9dbf 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/DataAccountSet.java @@ -14,9 +14,9 @@ public class DataAccountSet implements MerkleProvable, Transactional { private AccountSet accountSet; - public DataAccountSet(CryptoSetting cryptoSetting, String prefix,ExPolicyKVStorage exStorage, + public DataAccountSet(CryptoSetting cryptoSetting, String prefix, ExPolicyKVStorage exStorage, VersioningKVStorage verStorage, AccountAccessPolicy accessPolicy) { - accountSet = new AccountSet(cryptoSetting,prefix, exStorage, verStorage, accessPolicy); + accountSet = new AccountSet(cryptoSetting, prefix, exStorage, verStorage, accessPolicy); } public DataAccountSet(HashDigest dataRootHash, CryptoSetting cryptoSetting, String prefix, @@ -26,7 +26,7 @@ public class DataAccountSet implements MerkleProvable, Transactional { } public AccountHeader[] getAccounts(int fromIndex, int count) { - return accountSet.getAccounts(fromIndex,count); + return accountSet.getAccounts(fromIndex, count); } public boolean isReadonly() { @@ -56,8 +56,18 @@ public class DataAccountSet implements MerkleProvable, Transactional { return new DataAccount(accBase); } + /** + * 返回数据账户;
+ * 如果不存在,则返回 null; + * + * @param address + * @return + */ public DataAccount getDataAccount(Bytes address) { BaseAccount accBase = accountSet.getAccount(address); + if (accBase == null) { + return null; + } return new DataAccount(accBase); } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java index efa3e750..46c21655 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerEditor.java @@ -1,5 +1,6 @@ package com.jd.blockchain.ledger.core; +import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.LedgerTransaction; @@ -19,6 +20,20 @@ import com.jd.blockchain.ledger.TransactionRequest; public interface LedgerEditor { /** + * 账本Hash; + * + * @return + */ + HashDigest getLedgerHash(); + + /** + * 新区块的高度; + * + * @return + */ + long getBlockHeight(); + + /** * 开始新事务;
* * 方法返回之前,将会校验交易请求的用户签名列表和节点签名列表,并在后续对数据集 @@ -32,11 +47,14 @@ public interface LedgerEditor { * 或者全部回滚(通过方法 {@link LedgerTransactionContext#rollback()}),以此实现原子性写入; *

* - * 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存;

+ * 每一次事务性的账本写入操作在提交后,都会记录该事务相关的系统全局快照,以交易对象 {@link LedgerTransaction} 进行保存; + *

* - * 注:方法不解析、不执行交易中的操作; * - * @param txRequest + * + * 注:方法不解析、不执行交易中的操作;

+ * + * @param txRequest 交易请求; * @return */ LedgerTransactionContext newTransaction(TransactionRequest txRequest); diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java index 33f589c5..a4feb79e 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/LedgerTransactionContext.java @@ -24,7 +24,7 @@ public interface LedgerTransactionContext { * * @return */ - TransactionRequest getRequestTX(); + TransactionRequest getTransactionRequest(); /** * 提交对账本数据的修改,以指定的交易状态提交交易; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SettingContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SettingContext.java new file mode 100644 index 00000000..516b2acf --- /dev/null +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/SettingContext.java @@ -0,0 +1,51 @@ +package com.jd.blockchain.ledger.core; + +public class SettingContext { + + private static final TxSettingContext txSettings = new TxSettingContext(); + + private static final QueryingSettingContext queryingSettings = new QueryingSettingContext(); + + public static TxSettingContext txSettings() { + return txSettings; + } + + public static QueryingSettingContext queryingSettings() { + return queryingSettings; + } + + /** + * 与交易处理相关的设置; + * @author huanghaiquan + * + */ + public static class TxSettingContext { + + public boolean verifyLedger() { + return true; + } + + public boolean verifySignature() { + return true; + } + + } + + /** + * 与账本查询相关的设置; + * @author huanghaiquan + * + */ + public static class QueryingSettingContext { + + /** + * 查询区块等具有 hash 标识符的对象时是否重新校验哈希; + * @return + */ + public boolean verifyHash() { + return false; + } + + } + +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerBlockData.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerBlockData.java index 24b20401..1e8865b7 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerBlockData.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerBlockData.java @@ -33,7 +33,9 @@ public class LedgerBlockData implements LedgerBlock { // private HashDigest contractPrivilegeHash; private HashDigest transactionSetHash; - + + private long timestamp; + public LedgerBlockData() { } @@ -155,4 +157,14 @@ public class LedgerBlockData implements LedgerBlock { this.ledgerHash = ledgerHash; } + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + + } \ No newline at end of file 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 13625600..5696ded7 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 @@ -1,398 +1,399 @@ -package com.jd.blockchain.ledger.core.impl; - -import java.util.ArrayList; -import java.util.List; - -import com.jd.blockchain.contract.ContractException; -import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; -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.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; - -public class LedgerQueryService implements BlockchainQueryService { - - private LedgerService ledgerService; - - public LedgerQueryService(LedgerService ledgerService) { - this.ledgerService = ledgerService; - } - - @Override - public HashDigest[] getLedgerHashs() { - return ledgerService.getLedgerHashs(); - } - - @Override - public LedgerInfo getLedger(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerInfo ledgerInfo = new LedgerInfo(); - ledgerInfo.setHash(ledger.getHash()); - ledgerInfo.setLatestBlockHash(ledger.getLatestBlockHash()); - ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); - return ledgerInfo; - } - - @Override - public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { - return ledgerAdministration(ledgerHash).getParticipants(); - } - - @Override - public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { - return ledgerAdministration(ledgerHash).getMetadata(); - } - - @Override - public LedgerBlock getBlock(HashDigest ledgerHash, long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - return ledger.getBlock(height); - } - - @Override - public LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - return ledger.getBlock(blockHash); - } - - @Override - public long getTransactionCount(HashDigest ledgerHash, long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.getTotalCount(); - } - - @Override - public long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.getTotalCount(); - } - - @Override - public long getTransactionTotalCount(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.getTotalCount(); - } - - @Override - public long getDataAccountCount(HashDigest ledgerHash, long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @Override - public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @Override - public long getDataAccountTotalCount(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @Override - public long getUserCount(HashDigest ledgerHash, long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @Override - public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @Override - public long getUserTotalCount(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @Override - public long getContractCount(HashDigest ledgerHash, long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @Override - public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @Override - public long getContractTotalCount(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @Override - public LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock ledgerBlock = ledger.getBlock(height); - TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); - int lastHeightTxTotalNums = 0; - - if (height > 0) { - lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); - } - - int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); - // 取当前高度的增量交易数,在增量交易里进行查找 - int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; -// -// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { -// fromIndex = 0; -// } -// if (count == -1) { -// fromIndex = 0; -// count = currentHeightTxNums; -// } -// if (count > currentHeightTxNums) { -// count = currentHeightTxNums - fromIndex; -// } - int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); - return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); - } - - @Override - public LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock ledgerBlock = ledger.getBlock(blockHash); - long height = ledgerBlock.getHeight(); - TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); - int lastHeightTxTotalNums = 0; - - if (height > 0) { - lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); - } - - int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); - // 取当前块hash的增量交易数,在增量交易里进行查找 - int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; - -// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { -// fromIndex = 0; -// } -// if (count == -1) { -// fromIndex = 0; -// count = currentHeightTxNums; -// } -// if (count > currentHeightTxNums) { -// count = currentHeightTxNums - fromIndex; -// } - int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); - return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); - } - - @Override - public LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.get(contentHash); - } - - @Override - public TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.getTxState(contentHash); - } - - @Override - public UserInfo getUser(HashDigest ledgerHash, String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getUser(address); - - } - - @Override - public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - } - - @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { - if (keys == null || keys.length == 0) { - return null; - } - 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; - for (int i = 0; i < entries.length; i++) { - final String currKey = keys[i]; - - ver = dataAccount.getDataVersion(Bytes.fromString(currKey)); - - if (ver < 0) { - entries[i] = new KVDataObject(currKey, -1, null); - } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); - entries[i] = new KVDataObject(currKey, ver, value); - } - } - - 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, 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, null); - } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); - } - } - } - - return entries; - } - - @Override - public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { - - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - - return dataAccount.getDataEntries(fromIndex, count); - } - - @Override - public long getDataEntriesTotalCount(HashDigest ledgerHash, String address) { - - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - - return dataAccount.getDataEntriesTotalCount(); - } - - @Override - public ContractInfo getContract(HashDigest ledgerHash, String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getContract(Bytes.fromBase58(address)); - } - - @Override - public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); - return userAccountSet.getAccounts(pages[0], pages[1]); - } - - @Override - public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); - return dataAccountSet.getAccounts(pages[0], pages[1]); - } - - @Override - public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); - return contractAccountSet.getAccounts(pages[0], pages[1]); - } - - private LedgerAdministration ledgerAdministration(HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - LedgerAdministration administration = ledger.getAdminAccount(block); - return administration; - } -} +package com.jd.blockchain.ledger.core.impl; + +import java.util.ArrayList; +import java.util.List; + +import com.jd.blockchain.contract.ContractException; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.*; +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.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; + +public class LedgerQueryService implements BlockchainQueryService { + + private LedgerService ledgerService; + + public LedgerQueryService(LedgerService ledgerService) { + this.ledgerService = ledgerService; + } + + @Override + public HashDigest[] getLedgerHashs() { + return ledgerService.getLedgerHashs(); + } + + @Override + public LedgerInfo getLedger(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerInfo ledgerInfo = new LedgerInfo(); + ledgerInfo.setHash(ledger.getHash()); + ledgerInfo.setLatestBlockHash(ledger.getLatestBlockHash()); + ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); + return ledgerInfo; + } + + @Override + public ParticipantNode[] getConsensusParticipants(HashDigest ledgerHash) { + return ledgerAdministration(ledgerHash).getParticipants(); + } + + @Override + public LedgerMetadata getLedgerMetadata(HashDigest ledgerHash) { + return ledgerAdministration(ledgerHash).getMetadata(); + } + + @Override + public LedgerBlock getBlock(HashDigest ledgerHash, long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + return ledger.getBlock(height); + } + + @Override + public LedgerBlock getBlock(HashDigest ledgerHash, HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + return ledger.getBlock(blockHash); + } + + @Override + public long getTransactionCount(HashDigest ledgerHash, long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.getTotalCount(); + } + + @Override + public long getTransactionCount(HashDigest ledgerHash, HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.getTotalCount(); + } + + @Override + public long getTransactionTotalCount(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.getTotalCount(); + } + + @Override + public long getDataAccountCount(HashDigest ledgerHash, long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @Override + public long getDataAccountCount(HashDigest ledgerHash, HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @Override + public long getDataAccountTotalCount(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @Override + public long getUserCount(HashDigest ledgerHash, long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @Override + public long getUserCount(HashDigest ledgerHash, HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @Override + public long getUserTotalCount(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @Override + public long getContractCount(HashDigest ledgerHash, long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @Override + public long getContractCount(HashDigest ledgerHash, HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @Override + public long getContractTotalCount(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @Override + public LedgerTransaction[] getTransactions(HashDigest ledgerHash, long height, int fromIndex, int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock ledgerBlock = ledger.getBlock(height); + TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); + int lastHeightTxTotalNums = 0; + + if (height > 0) { + lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); + } + + int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); + // 取当前高度的增量交易数,在增量交易里进行查找 + int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; +// +// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { +// fromIndex = 0; +// } +// if (count == -1) { +// fromIndex = 0; +// count = currentHeightTxNums; +// } +// if (count > currentHeightTxNums) { +// count = currentHeightTxNums - fromIndex; +// } + int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); + return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); + } + + @Override + public LedgerTransaction[] getTransactions(HashDigest ledgerHash, HashDigest blockHash, int fromIndex, int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock ledgerBlock = ledger.getBlock(blockHash); + long height = ledgerBlock.getHeight(); + TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); + int lastHeightTxTotalNums = 0; + + if (height > 0) { + lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); + } + + int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); + // 取当前块hash的增量交易数,在增量交易里进行查找 + int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; + +// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { +// fromIndex = 0; +// } +// if (count == -1) { +// fromIndex = 0; +// count = currentHeightTxNums; +// } +// if (count > currentHeightTxNums) { +// count = currentHeightTxNums - fromIndex; +// } + int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); + return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); + } + + @Override + public LedgerTransaction getTransactionByContentHash(HashDigest ledgerHash, HashDigest contentHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.get(contentHash); + } + + @Override + public TransactionState getTransactionStateByContentHash(HashDigest ledgerHash, HashDigest contentHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.getTxState(contentHash); + } + + @Override + public UserInfo getUser(HashDigest ledgerHash, String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getUser(address); + + } + + @Override + public AccountHeader getDataAccount(HashDigest ledgerHash, String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + } + + @Override + public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, String... keys) { + if (keys == null || keys.length == 0) { + return null; + } + 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; + for (int i = 0; i < entries.length; i++) { + final String currKey = keys[i]; + + ver = dataAccount.getDataVersion(Bytes.fromString(currKey)); + + if (ver < 0) { + entries[i] = new KVDataObject(currKey, -1, null); + } else { + BytesValue value = dataAccount.getBytes(Bytes.fromString(currKey), ver); + entries[i] = new KVDataObject(currKey, ver, value); + } + } + + 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, 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, null); + } else { + BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); + entries[i] = new KVDataObject(keys[i], ver, value); + } + } + } + + return entries; + } + + @Override + public KVDataEntry[] getDataEntries(HashDigest ledgerHash, String address, int fromIndex, int count) { + + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); + return dataAccount.getDataEntries(pages[0], pages[1]); + } + + @Override + public long getDataEntriesTotalCount(HashDigest ledgerHash, String address) { + + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + + return dataAccount.getDataEntriesTotalCount(); + } + + @Override + public ContractInfo getContract(HashDigest ledgerHash, String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getContract(Bytes.fromBase58(address)); + } + + @Override + public AccountHeader[] getUsers(HashDigest ledgerHash, int fromIndex, int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); + return userAccountSet.getAccounts(pages[0], pages[1]); + } + + @Override + public AccountHeader[] getDataAccounts(HashDigest ledgerHash, int fromIndex, int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); + return dataAccountSet.getAccounts(pages[0], pages[1]); + } + + @Override + public AccountHeader[] getContractAccounts(HashDigest ledgerHash, int fromIndex, int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); + return contractAccountSet.getAccounts(pages[0], pages[1]); + } + + private LedgerAdministration ledgerAdministration(HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + LedgerAdministration administration = ledger.getAdminAccount(block); + return administration; + } +} diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java index 69e3223f..1fe559b7 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerRepositoryImpl.java @@ -15,6 +15,7 @@ import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerRepository; import com.jd.blockchain.ledger.core.LedgerTransactionContext; +import com.jd.blockchain.ledger.core.SettingContext; import com.jd.blockchain.ledger.core.TransactionSet; import com.jd.blockchain.ledger.core.UserAccountSet; import com.jd.blockchain.storage.service.ExPolicyKVStorage; @@ -77,7 +78,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { this.ledgerIndexKey = encodeLedgerIndexKey(ledgerHash); if (getLatestBlockHeight() < 0) { - throw new LedgerException("Ledger doesn't exist!"); + throw new RuntimeException("Ledger doesn't exist!"); } } @@ -205,15 +206,14 @@ public class LedgerRepositoryImpl implements LedgerRepository { LedgerBlockData block = new LedgerBlockData(deserialize(blockBytes)); if (!blockHash.equals(block.getHash())) { - throw new LedgerException("Block hash not equals to it's storage key!"); + throw new RuntimeException("Block hash not equals to it's storage key!"); } // verify hash; // boolean requiredVerifyHash = // adminAccount.getMetadata().getSetting().getCryptoSetting().getAutoVerifyHash(); // TODO: 未实现从配置中加载是否校验 Hash 的设置; - boolean requiredVerifyHash = false; - if (requiredVerifyHash) { + if (SettingContext.queryingSettings().verifyHash()) { byte[] blockBodyBytes = null; if (block.getHeight() == 0) { // 计算创世区块的 hash 时,不包括 ledgerHash 字段; @@ -227,14 +227,14 @@ public class LedgerRepositoryImpl implements LedgerRepository { HashFunction hashFunc = Crypto.getHashFunction(blockHash.getAlgorithm()); boolean pass = hashFunc.verify(blockHash, blockBodyBytes); if (!pass) { - throw new LedgerException("Block hash verification fail!"); + throw new RuntimeException("Block hash verification fail!"); } } // verify height; HashDigest indexedHash = getBlockHash(block.getHeight()); if (indexedHash == null || !indexedHash.equals(blockHash)) { - throw new LedgerException( + throw new RuntimeException( "Illegal ledger state in storage that ledger height index doesn't match it's block data in height[" + block.getHeight() + "] and block hash[" + Base58Utils.encode(blockHash.toBytes()) + "] !"); @@ -394,15 +394,15 @@ public class LedgerRepositoryImpl implements LedgerRepository { @Override public synchronized LedgerEditor createNextBlock() { if (closed) { - throw new LedgerException("Ledger repository has been closed!"); + throw new RuntimeException("Ledger repository has been closed!"); } if (this.nextBlockEditor != null) { - throw new LedgerException( + throw new RuntimeException( "A new block is in process, cann't create another one until it finish by committing or canceling."); } LedgerBlock previousBlock = getLatestBlock(); - LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor( - getAdminInfo().getMetadata().getSetting(), previousBlock, keyPrefix, exPolicyStorage, + LedgerTransactionalEditor editor = LedgerTransactionalEditor.createEditor(previousBlock, + getAdminInfo().getMetadata().getSetting(), keyPrefix, exPolicyStorage, versioningStorage); NewBlockCommittingMonitor committingMonitor = new NewBlockCommittingMonitor(editor, this); this.nextBlockEditor = committingMonitor; @@ -420,7 +420,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { return; } if (this.nextBlockEditor != null) { - throw new LedgerException("A new block is in process, cann't close the ledger repository!"); + throw new RuntimeException("A new block is in process, cann't close the ledger repository!"); } closed = true; } @@ -479,7 +479,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { } static TransactionSet newTransactionSet(LedgerSetting ledgerSetting, String keyPrefix, - ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { + ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { // TransactionSet transactionSet = new // TransactionSet(ledgerSetting.getCryptoSetting(), // PrefixAppender.prefix(TRANSACTION_SET_PREFIX, ledgerExStorage), @@ -577,6 +577,16 @@ public class LedgerRepositoryImpl implements LedgerRepository { } @Override + public HashDigest getLedgerHash() { + return editor.getLedgerHash(); + } + + @Override + public long getBlockHeight() { + return editor.getBlockHeight(); + } + + @Override public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { return editor.newTransaction(txRequest); } @@ -590,7 +600,7 @@ public class LedgerRepositoryImpl implements LedgerRepository { public void commit() { try { editor.commit(); - LedgerBlock latestBlock = editor.getNewlyBlock(); + LedgerBlock latestBlock = editor.getCurrentBlock(); ledgerRepo.latestState = new LedgerState(latestBlock); } finally { ledgerRepo.nextBlockEditor = null; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java index 6e231b44..432c24e1 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionData.java @@ -1,8 +1,5 @@ package com.jd.blockchain.ledger.core.impl; -import java.util.Arrays; -import java.util.Comparator; - import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.DigitalSignature; import com.jd.blockchain.ledger.LedgerTransaction; @@ -29,48 +26,27 @@ public class LedgerTransactionData implements LedgerTransaction { private OperationResult[] operationResults; - // private HashDigest adminAccountHash; - // - // private HashDigest userAccountSetHash; - // - // private HashDigest dataAccountSetHash; - // - // private HashDigest contractAccountSetHash; - /** * Declare a private no-arguments constructor for deserializing purpose; */ + @SuppressWarnings("unused") private LedgerTransactionData() { -// this.txSnapshot = new TransactionStagedSnapshot(); } /** - * @param blockHeight - * 区块链高度; - * @param txReq - * 交易请求; - * @param execState - * 执行状态; - * @param txSnapshot - * 交易级的系统快照; + * @param blockHeight 区块链高度; + * @param txReq 交易请求; + * @param execState 执行状态; + * @param txSnapshot 交易级的系统快照; */ public LedgerTransactionData(long blockHeight, TransactionRequest txReq, TransactionState execState, TransactionStagedSnapshot txSnapshot, OperationResult... opResults) { this.blockHeight = blockHeight; -// this.txSnapshot = txSnapshot == null ? new TransactionStagedSnapshot() : txSnapshot; this.txSnapshot = txSnapshot; this.transactionContent = txReq.getTransactionContent(); this.endpointSignatures = txReq.getEndpointSignatures(); this.nodeSignatures = txReq.getNodeSignatures(); this.executionState = execState; - if (opResults != null) { - Arrays.sort(opResults, new Comparator() { - @Override - public int compare(OperationResult o1, OperationResult o2) { - return o1.getIndex() - o2.getIndex(); - } - }); - } this.operationResults = opResults; } @@ -116,17 +92,17 @@ public class LedgerTransactionData implements LedgerTransaction { @Override public HashDigest getUserAccountSetHash() { - return txSnapshot == null ? null :txSnapshot.getUserAccountSetHash(); + return txSnapshot == null ? null : txSnapshot.getUserAccountSetHash(); } @Override public HashDigest getDataAccountSetHash() { - return txSnapshot == null ? null :txSnapshot.getDataAccountSetHash(); + return txSnapshot == null ? null : txSnapshot.getDataAccountSetHash(); } @Override public HashDigest getContractAccountSetHash() { - return txSnapshot == null ? null :txSnapshot.getContractAccountSetHash(); + return txSnapshot == null ? null : txSnapshot.getContractAccountSetHash(); } public void setTxSnapshot(TransactionStagedSnapshot txSnapshot) { @@ -140,20 +116,22 @@ public class LedgerTransactionData implements LedgerTransaction { this.transactionContent = content; } - public void setEndpointSignatures(Object[] participantSignatures) { - int length = participantSignatures.length; - this.endpointSignatures = new DigitalSignature[length]; - for (int i = 0; i < length; i++) { - this.endpointSignatures[i] = (DigitalSignature) participantSignatures[i]; - } + public void setEndpointSignatures(DigitalSignature[] participantSignatures) { + this.endpointSignatures = participantSignatures; +// int length = participantSignatures.length; +// this.endpointSignatures = new DigitalSignature[length]; +// for (int i = 0; i < length; i++) { +// this.endpointSignatures[i] = (DigitalSignature) participantSignatures[i]; +// } } - public void setNodeSignatures(Object[] nodeSignatures) { - int length = nodeSignatures.length; - this.nodeSignatures = new DigitalSignature[length]; - for (int i = 0; i < length; i++) { - this.nodeSignatures[i] = (DigitalSignature) nodeSignatures[i]; - } + public void setNodeSignatures(DigitalSignature[] nodeSignatures) { + this.nodeSignatures = nodeSignatures; +// int length = nodeSignatures.length; +// this.nodeSignatures = new DigitalSignature[length]; +// for (int i = 0; i < length; i++) { +// this.nodeSignatures[i] = (DigitalSignature) nodeSignatures[i]; +// } } public void setExecutionState(TransactionState executionState) { diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java index d939c865..235d08b8 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/LedgerTransactionalEditor.java @@ -1,19 +1,35 @@ package com.jd.blockchain.ledger.core.impl; import java.util.List; -import java.util.Stack; import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.crypto.Crypto; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.BlockBody; +import com.jd.blockchain.ledger.BlockRollbackException; +import com.jd.blockchain.ledger.CryptoSetting; +import com.jd.blockchain.ledger.DigitalSignature; +import com.jd.blockchain.ledger.IllegalTransactionException; +import com.jd.blockchain.ledger.LedgerBlock; +import com.jd.blockchain.ledger.LedgerDataSnapshot; +import com.jd.blockchain.ledger.LedgerInitSetting; +import com.jd.blockchain.ledger.LedgerSetting; +import com.jd.blockchain.ledger.LedgerTransaction; +import com.jd.blockchain.ledger.OperationResult; +import com.jd.blockchain.ledger.TransactionContent; +import com.jd.blockchain.ledger.TransactionRequest; +import com.jd.blockchain.ledger.TransactionRollbackException; +import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerTransactionContext; +import com.jd.blockchain.ledger.core.SettingContext; import com.jd.blockchain.ledger.core.TransactionSet; import com.jd.blockchain.storage.service.ExPolicyKVStorage; import com.jd.blockchain.storage.service.VersioningKVStorage; import com.jd.blockchain.storage.service.utils.BufferedKVStorage; +import com.jd.blockchain.transaction.TxBuilder; +import com.jd.blockchain.transaction.TxRequestBuilder; import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.codec.Base58Utils; @@ -26,13 +42,18 @@ public class LedgerTransactionalEditor implements LedgerEditor { System.out.println("------ [[ parallel-dbwrite=" + PARALLEL_DB_WRITE + " ]] ------"); } + /** + * 账本Hash,创世区块的编辑器则返回 null; + */ + private HashDigest ledgerHash; + private final String ledgerKeyPrefix; private CryptoSetting cryptoSetting; - private LedgerBlockData newlyBlock; + private LedgerBlockData currentBlock; - private Stack stagedSnapshots = new Stack<>(); +// private Stack stagedSnapshots = new Stack<>(); private boolean prepared = false; @@ -40,29 +61,70 @@ public class LedgerTransactionalEditor implements LedgerEditor { private boolean committed = false; - private BufferedKVStorage bufferedStorage; + private StagedSnapshot startingPoint; + + /** + * 当前区块的存储; + */ + private BufferedKVStorage baseStorage; /** - * 最近一个交易上下文; + * 上一个交易的上下文; */ - private LedgerDataContext lastTxCtx; +// private LedgerTransactionContextImpl previousTxCtx; - private LedgerDataContext newTxCtx; + private TxSnapshot previousTxSnapshot; - private LedgerTransactionalEditor(CryptoSetting cryptoSetting, LedgerBlockData newlyBlock, + /** + * 当前交易的上下文; + */ + private volatile LedgerTransactionContextImpl currentTxCtx; + + /** + * @param ledgerHash + * @param cryptoSetting + * @param currentBlock + * @param startingPoint + * @param ledgerKeyPrefix + * @param bufferedStorage + * @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; + */ + private LedgerTransactionalEditor(HashDigest ledgerHash, CryptoSetting cryptoSetting, LedgerBlockData currentBlock, StagedSnapshot startingPoint, String ledgerKeyPrefix, BufferedKVStorage bufferedStorage) { + this.ledgerHash = ledgerHash; this.ledgerKeyPrefix = ledgerKeyPrefix; this.cryptoSetting = cryptoSetting; - this.newlyBlock = newlyBlock; - this.bufferedStorage = bufferedStorage; + this.currentBlock = currentBlock; + this.baseStorage = bufferedStorage; + + this.startingPoint = startingPoint; - this.stagedSnapshots.push(startingPoint); +// this.stagedSnapshots.push(startingPoint); } - public static LedgerTransactionalEditor createEditor(LedgerSetting ledgerSetting, LedgerBlock previousBlock, + /** + * 创建账本新区块的编辑器; + * + * @param ledgerHash 账本哈希; + * @param ledgerSetting 账本设置; + * @param previousBlock 前置区块; + * @param ledgerKeyPrefix 账本数据前缀; + * @param ledgerExStorage 账本数据存储; + * @param ledgerVerStorage 账本数据版本化存储; + * @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; + * @return + */ + public static LedgerTransactionalEditor createEditor(LedgerBlock previousBlock, LedgerSetting ledgerSetting, String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { // new block; - LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, previousBlock.getLedgerHash(), + HashDigest ledgerHash = previousBlock.getLedgerHash(); + if (ledgerHash == null) { + ledgerHash = previousBlock.getHash(); + } + if (ledgerHash == null) { + throw new IllegalArgumentException("Illegal previous block was specified!"); + } + LedgerBlockData currBlock = new LedgerBlockData(previousBlock.getHeight() + 1, ledgerHash, previousBlock.getHash()); // init storage; @@ -71,163 +133,246 @@ public class LedgerTransactionalEditor implements LedgerEditor { StagedSnapshot startingPoint = new TxSnapshot(previousBlock, previousBlock.getTransactionSetHash()); // instantiate editor; - return new LedgerTransactionalEditor(ledgerSetting.getCryptoSetting(), currBlock, startingPoint, + return new LedgerTransactionalEditor(ledgerHash, ledgerSetting.getCryptoSetting(), currBlock, startingPoint, ledgerKeyPrefix, txStagedStorage); } + /** + * 创建创世区块的编辑器; + * + * @param initSetting + * @param ledgerKeyPrefix + * @param ledgerExStorage + * @param ledgerVerStorage + * @param verifyTx 是否校验交易请求;当外部调用者在调用前已经实施了验证时,将次参数设置为 false 能够提升性能; + * @return + */ public static LedgerTransactionalEditor createEditor(LedgerInitSetting initSetting, String ledgerKeyPrefix, ExPolicyKVStorage ledgerExStorage, VersioningKVStorage ledgerVerStorage) { LedgerBlockData genesisBlock = new LedgerBlockData(0, null, null); StagedSnapshot startingPoint = new GenesisSnapshot(initSetting); // init storage; BufferedKVStorage txStagedStorage = new BufferedKVStorage(ledgerExStorage, ledgerVerStorage, false); - return new LedgerTransactionalEditor(initSetting.getCryptoSetting(), genesisBlock, startingPoint, + return new LedgerTransactionalEditor(null, initSetting.getCryptoSetting(), genesisBlock, startingPoint, ledgerKeyPrefix, txStagedStorage); } private void commitTxSnapshot(TxSnapshot snapshot) { - lastTxCtx = newTxCtx; - newTxCtx = null; - stagedSnapshots.push(snapshot); + previousTxSnapshot = snapshot; + currentTxCtx = null; } - private void rollbackNewTx() { - newTxCtx = null; + private void rollbackCurrentTx() { + currentTxCtx = null; } - // public LedgerDataSet getLatestDataSet() { - // if (lastTxCtx == null) { - // return null; - // } - // return lastTxCtx.getDataSet(); - // } + LedgerBlock getCurrentBlock() { + return currentBlock; + } - public LedgerBlock getNewlyBlock() { - return newlyBlock; + @Override + public long getBlockHeight() { + return currentBlock.getHeight(); } @Override - public LedgerTransactionContext newTransaction(TransactionRequest txRequest) { + public HashDigest getLedgerHash() { + return ledgerHash; + } + + /** + * 检查当前账本是否是指定交易请求的账本; + * + * @param txRequest + * @return + */ + private boolean isRequestedLedger(TransactionRequest txRequest) { + HashDigest reqLedgerHash = txRequest.getTransactionContent().getLedgerHash(); + if (ledgerHash == reqLedgerHash) { + return true; + } + if (ledgerHash == null || reqLedgerHash == null) { + return false; + } + return ledgerHash.equals(reqLedgerHash); + } + + private boolean verifyTxContent(TransactionRequest request) { + TransactionContent txContent = request.getTransactionContent(); + if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { + return false; + } + DigitalSignature[] endpointSignatures = request.getEndpointSignatures(); + if (endpointSignatures != null) { + for (DigitalSignature signature : endpointSignatures) { + if (!TxRequestBuilder.verifyHashSignature(txContent.getHash(), signature.getDigest(), + signature.getPubKey())) { + return false; + } + } + } + DigitalSignature[] nodeSignatures = request.getNodeSignatures(); + if (nodeSignatures != null) { + for (DigitalSignature signature : nodeSignatures) { + if (!TxRequestBuilder.verifyHashSignature(txContent.getHash(), signature.getDigest(), + signature.getPubKey())) { + return false; + } + } + } + return true; + } + + @Override + public synchronized LedgerTransactionContext newTransaction(TransactionRequest txRequest) { + if (SettingContext.txSettings().verifyLedger() && !isRequestedLedger(txRequest)) { + throw new IllegalTransactionException( + "Transaction request is dispatched to a wrong ledger! --[TxHash=" + + txRequest.getTransactionContent().getHash() + "]!", + TransactionState.IGNORED_BY_WRONG_LEDGER); + } + + // TODO: 把验签和创建交易并行化; + if (SettingContext.txSettings().verifySignature() && !verifyTxContent(txRequest)) { + // 抛弃哈希和签名校验失败的交易请求; + throw new IllegalTransactionException( + "Wrong transaction signature! --[TxHash=" + txRequest.getTransactionContent().getHash() + "]!", + TransactionState.IGNORED_BY_WRONG_CONTENT_SIGNATURE); + } + + if (currentTxCtx != null) { + throw new IllegalStateException( + "Unable to open another new transaction before the current transaction is completed! --[TxHash=" + + txRequest.getTransactionContent().getHash() + "]!"); + } + + // 检查状态是否允许创建新的交易请求;; checkState(); - // TODO:验证交易签名; - BufferedKVStorage txBuffStorage = null; + // init storage of new transaction; + BufferedKVStorage txBufferedStorage = new BufferedKVStorage(baseStorage, baseStorage, false); + LedgerDataSetImpl txDataset = null; TransactionSet txset = null; - if (lastTxCtx == null) { - // init storage of new transaction; - // txBuffStorage = new BufferedKVStorage(bufferedStorage, bufferedStorage, - // false); - txBuffStorage = bufferedStorage; - + if (previousTxSnapshot == null) { // load the starting point of the new transaction; - StagedSnapshot previousSnapshot = stagedSnapshots.peek(); - if (previousSnapshot instanceof GenesisSnapshot) { + if (startingPoint instanceof GenesisSnapshot) { // 准备生成创世区块; - GenesisSnapshot snpht = (GenesisSnapshot) previousSnapshot; - txDataset = LedgerRepositoryImpl.newDataSet(snpht.initSetting, ledgerKeyPrefix, txBuffStorage, - txBuffStorage); + GenesisSnapshot snpht = (GenesisSnapshot) startingPoint; + txDataset = LedgerRepositoryImpl.newDataSet(snpht.initSetting, ledgerKeyPrefix, txBufferedStorage, + txBufferedStorage); txset = LedgerRepositoryImpl.newTransactionSet(txDataset.getAdminAccount().getSetting(), - ledgerKeyPrefix, txBuffStorage, txBuffStorage); - } else { + ledgerKeyPrefix, txBufferedStorage, txBufferedStorage); + } else if (startingPoint instanceof TxSnapshot) { // 新的区块; // TxSnapshot; reload dataset and txset; - TxSnapshot snpht = (TxSnapshot) previousSnapshot; + TxSnapshot snpht = (TxSnapshot) startingPoint; // load dataset; - txDataset = LedgerRepositoryImpl.loadDataSet(snpht.dataSnapshot, ledgerKeyPrefix, txBuffStorage, - txBuffStorage, false); + txDataset = LedgerRepositoryImpl.loadDataSet(snpht.dataSnapshot, ledgerKeyPrefix, txBufferedStorage, + txBufferedStorage, false); - // load tx set; - txset = LedgerRepositoryImpl.loadTransactionSet(snpht.transactionSetHash, this.cryptoSetting, - ledgerKeyPrefix, txBuffStorage, txBuffStorage, false); + // load txset; + txset = LedgerRepositoryImpl.loadTransactionSet(snpht.txsetHash, this.cryptoSetting, ledgerKeyPrefix, + txBufferedStorage, txBufferedStorage, false); + } else { + // Unreachable; + throw new IllegalStateException("Unreachable code was accidentally executed!"); } - lastTxCtx = new LedgerDataContext(txDataset, txset, txBuffStorage); } else { // Reuse previous object to optimize performance; - txBuffStorage = lastTxCtx.storage; - txDataset = lastTxCtx.dataset; - txset = lastTxCtx.txset; + // load dataset; + txDataset = LedgerRepositoryImpl.loadDataSet(previousTxSnapshot.dataSnapshot, ledgerKeyPrefix, + txBufferedStorage, txBufferedStorage, false); + + // load txset; + txset = LedgerRepositoryImpl.loadTransactionSet(previousTxSnapshot.txsetHash, this.cryptoSetting, + ledgerKeyPrefix, txBufferedStorage, txBufferedStorage, false); } - // newTxCtx = new LedgerTransactionContextImpl(newlyBlock.getHeight(), - // txRequest, txDataset, txset, txBuffStorage, - // this); - // return newTxCtx; + currentTxCtx = new LedgerTransactionContextImpl(txRequest, txDataset, txset, txBufferedStorage, this); - return new LedgerTransactionContextImpl(newlyBlock.getHeight(), txRequest, txDataset, txset, txBuffStorage, - this); + return currentTxCtx; } @Override public LedgerBlock prepare() { checkState(); - if (newTxCtx != null) { - throw new IllegalStateException("There is a opening transaction which isn't committed or rollbacked!"); + if (currentTxCtx != null) { + // 有进行中的交易尚未提交或回滚; + throw new IllegalStateException( + "There is an ongoing transaction that has been not committed or rolled back!"); } - if (lastTxCtx == null) { - // Genesis; - throw new IllegalStateException("No transaction to prepare!"); + if (previousTxSnapshot == null) { + // 当前区块没有加入过交易,不允许产生空区块; + throw new IllegalStateException( + "There is no transaction in the current block, and no empty blocks is allowed!"); } // do commit when transaction isolation level is BLOCK; - lastTxCtx.dataset.commit(); - lastTxCtx.txset.commit(); + currentBlock.setAdminAccountHash(previousTxSnapshot.getAdminAccountHash()); + currentBlock.setUserAccountSetHash(previousTxSnapshot.getUserAccountSetHash()); + currentBlock.setDataAccountSetHash(previousTxSnapshot.getDataAccountSetHash()); + currentBlock.setContractAccountSetHash(previousTxSnapshot.getContractAccountSetHash()); + currentBlock.setTransactionSetHash(previousTxSnapshot.getTransactionSetHash()); - newlyBlock.setAdminAccountHash(lastTxCtx.dataset.getAdminAccount().getHash()); - newlyBlock.setContractAccountSetHash(lastTxCtx.dataset.getContractAccountSet().getRootHash()); - newlyBlock.setDataAccountSetHash(lastTxCtx.dataset.getDataAccountSet().getRootHash()); - newlyBlock.setUserAccountSetHash(lastTxCtx.dataset.getUserAccountSet().getRootHash()); - newlyBlock.setTransactionSetHash(lastTxCtx.txset.getRootHash()); + // TODO: 根据所有交易的时间戳的平均值来生成区块的时间戳; +// long timestamp = +// currentBlock.setTimestamp(timestamp); // compute block hash; - byte[] blockBodyBytes = BinaryProtocol.encode(newlyBlock, BlockBody.class); + byte[] blockBodyBytes = BinaryProtocol.encode(currentBlock, BlockBody.class); HashDigest blockHash = Crypto.getHashFunction(cryptoSetting.getHashAlgorithm()).hash(blockBodyBytes); - newlyBlock.setHash(blockHash); - if (newlyBlock.getLedgerHash() == null) { - // init GenesisBlock's ledger hash; - newlyBlock.setLedgerHash(blockHash); - } + currentBlock.setHash(blockHash); + +// if (currentBlock.getLedgerHash() == null) { +// // init GenesisBlock's ledger hash; +// currentBlock.setLedgerHash(blockHash); +// } // persist block bytes; // only one version per block; - byte[] blockBytes = BinaryProtocol.encode(newlyBlock, LedgerBlock.class); - Bytes blockStorageKey = LedgerRepositoryImpl.encodeBlockStorageKey(newlyBlock.getHash()); - long v = bufferedStorage.set(blockStorageKey, blockBytes, -1); + byte[] blockBytes = BinaryProtocol.encode(currentBlock, LedgerBlock.class); + Bytes blockStorageKey = LedgerRepositoryImpl.encodeBlockStorageKey(currentBlock.getHash()); + long v = baseStorage.set(blockStorageKey, blockBytes, -1); if (v < 0) { throw new IllegalStateException( - "Block already exist! --[BlockHash=" + Base58Utils.encode(newlyBlock.getHash().toBytes()) + "]"); + "Block already exist! --[BlockHash=" + Base58Utils.encode(currentBlock.getHash().toBytes()) + "]"); } // persist block hash to ledger index; - HashDigest ledgerHash = newlyBlock.getLedgerHash(); + HashDigest ledgerHash = currentBlock.getLedgerHash(); + if (ledgerHash == null) { + ledgerHash = blockHash; + } Bytes ledgerIndexKey = LedgerRepositoryImpl.encodeLedgerIndexKey(ledgerHash); - long expectedVersion = newlyBlock.getHeight() - 1; - v = bufferedStorage.set(ledgerIndexKey, newlyBlock.getHash().toBytes(), expectedVersion); + long expectedVersion = currentBlock.getHeight() - 1; + v = baseStorage.set(ledgerIndexKey, currentBlock.getHash().toBytes(), expectedVersion); if (v < 0) { - throw new IllegalStateException("Index of BlockHash already exist! --[BlockHash=" - + Base58Utils.encode(newlyBlock.getHash().toBytes()) + "]"); + throw new IllegalStateException( + String.format("Index of BlockHash already exist! --[BlockHeight=%s][BlockHash=%s]", + currentBlock.getHeight(), currentBlock.getHash())); } prepared = true; - return newlyBlock; + return currentBlock; } @Override public void commit() { if (committed) { - throw new IllegalStateException("LedgerEditor had been committed!"); + throw new IllegalStateException("The current block has been committed!"); } if (canceled) { - throw new IllegalStateException("LedgerEditor had been canceled!"); + throw new IllegalStateException("The current block has been canceled!"); } if (!prepared) { // 未就绪; - throw new IllegalStateException("LedgerEditor has not prepared!"); + throw new IllegalStateException("The current block is not ready yet!"); } - bufferedStorage.flush(); + baseStorage.flush(); committed = true; } @@ -235,38 +380,47 @@ public class LedgerTransactionalEditor implements LedgerEditor { @Override public void cancel() { if (committed) { - throw new IllegalStateException("LedgerEditor had been committed!"); + throw new IllegalStateException("The current block has been committed!"); } if (canceled) { return; } canceled = true; - // if (newTxCtx != null) { - // newTxCtx.rollback(); - // newTxCtx = null; - // } - bufferedStorage.cancel(); + + baseStorage.cancel(); } private void checkState() { if (prepared) { - throw new IllegalStateException("LedgerEditor has been prepared!"); + throw new IllegalStateException("The current block is ready!"); } if (committed) { - throw new IllegalStateException("LedgerEditor has been committed!"); + throw new IllegalStateException("The current block has been committed!"); } if (canceled) { - throw new IllegalStateException("LedgerEditor has been canceled!"); + throw new IllegalStateException("The current block has been canceled!"); } } // --------------------------- inner type -------------------------- + /** + * 用于暂存交易上下文数据的快照对象; + * + * @author huanghaiquan + * + */ private static interface StagedSnapshot { } + /** + * 创世区块的快照对象; + * + * @author huanghaiquan + * + */ private static class GenesisSnapshot implements StagedSnapshot { private LedgerInitSetting initSetting; @@ -276,6 +430,12 @@ public class LedgerTransactionalEditor implements LedgerEditor { } } + /** + * 交易执行完毕后的快照对象; + * + * @author huanghaiquan + * + */ private static class TxSnapshot implements StagedSnapshot { /** @@ -286,58 +446,90 @@ public class LedgerTransactionalEditor implements LedgerEditor { /** * 交易集合的快照(根哈希); */ - private HashDigest transactionSetHash; + private HashDigest txsetHash; - public TxSnapshot(LedgerDataSnapshot dataSnapshot, HashDigest txSetHash) { - this.dataSnapshot = dataSnapshot; - this.transactionSetHash = txSetHash; + public HashDigest getAdminAccountHash() { + return dataSnapshot.getAdminAccountHash(); } - } - - private static class LedgerDataContext { + public HashDigest getUserAccountSetHash() { + return dataSnapshot.getUserAccountSetHash(); + } - protected LedgerDataSetImpl dataset; + public HashDigest getDataAccountSetHash() { + return dataSnapshot.getDataAccountSetHash(); + } - protected TransactionSet txset; + public HashDigest getContractAccountSetHash() { + return dataSnapshot.getContractAccountSetHash(); + } - protected BufferedKVStorage storage; + public HashDigest getTransactionSetHash() { + return txsetHash; + } - public LedgerDataContext(LedgerDataSetImpl dataset, TransactionSet txset, BufferedKVStorage storage) { - this.dataset = dataset; - this.txset = txset; - this.storage = storage; + public TxSnapshot(LedgerDataSnapshot dataSnapshot, HashDigest txsetHash) { + this.dataSnapshot = dataSnapshot; + this.txsetHash = txsetHash; } } - private static class LedgerTransactionContextImpl extends LedgerDataContext implements LedgerTransactionContext { +// /** +// * 账本的数据上下文; +// * +// * @author huanghaiquan +// * +// */ +// private static class LedgerDataContext { +// +// protected LedgerDataSetImpl dataset; +// +// protected TransactionSet txset; +// +// protected BufferedKVStorage storage; +// +// public LedgerDataContext(LedgerDataSetImpl dataset, TransactionSet txset, BufferedKVStorage storage) { +// this.dataset = dataset; +// this.txset = txset; +// this.storage = storage; +// } +// +// } - private long blockHeight; + /** + * 交易的上下文; + * + * @author huanghaiquan + * + */ + private static class LedgerTransactionContextImpl implements LedgerTransactionContext { - private LedgerTransactionalEditor editor; + private LedgerTransactionalEditor blockEditor; private TransactionRequest txRequest; - // private LedgerDataSetImpl dataset; - // - // private TransactionSet txset; - // - // private BufferedKVStorage storage; + private LedgerDataSetImpl dataset; + + private TransactionSet txset; + + private BufferedKVStorage storage; private boolean committed = false; private boolean rollbacked = false; - private LedgerTransactionContextImpl(long blockHeight, TransactionRequest txRequest, LedgerDataSetImpl dataset, + private LedgerTransaction transaction; + + private HashDigest txRootHash; + + private LedgerTransactionContextImpl(TransactionRequest txRequest, LedgerDataSetImpl dataset, TransactionSet txset, BufferedKVStorage storage, LedgerTransactionalEditor editor) { - super(dataset, txset, storage); this.txRequest = txRequest; - // this.dataset = dataset; - // this.txset = txset; - // this.storage = storage; - this.editor = editor; - this.blockHeight = blockHeight; + this.dataset = dataset; + this.txset = txset; + this.storage = storage; + this.blockEditor = editor; } @Override @@ -346,7 +538,7 @@ public class LedgerTransactionalEditor implements LedgerEditor { } @Override - public TransactionRequest getRequestTX() { + public TransactionRequest getTransactionRequest() { return txRequest; } @@ -360,24 +552,28 @@ public class LedgerTransactionalEditor implements LedgerEditor { checkTxState(); // capture snapshot - // this.dataset.commit(); - // TransactionStagedSnapshot txDataSnapshot = takeSnapshot(); - - // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, - // txResult, txDataSnapshot); - - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, - operationResultArray(operationResults)); - this.txset.add(tx); - // this.txset.commit(); - - // this.storage.flush(); + this.dataset.commit(); + TransactionStagedSnapshot txDataSnapshot = takeDataSnapshot(); + + LedgerTransactionData tx; + try { + tx = new LedgerTransactionData(blockEditor.getBlockHeight(), txRequest, txResult, txDataSnapshot, + operationResultArray(operationResults)); + this.txset.add(tx); + this.txset.commit(); + } catch (Exception e) { + throw new TransactionRollbackException(e.getMessage(), e); + } - // TODO: 未处理出错时 dataset 和 txset 的内部状态恢复,有可能出现不一致的情况; + try { + this.storage.flush(); + } catch (Exception e) { + throw new BlockRollbackException(e.getMessage(), e); + } // put snapshot into stack; - // TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); - // editor.commitTxSnapshot(snapshot); + TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); + blockEditor.commitTxSnapshot(snapshot); committed = true; return tx; @@ -393,29 +589,35 @@ public class LedgerTransactionalEditor implements LedgerEditor { checkTxState(); // 未处理 - // dataset.cancel(); - - // TransactionStagedSnapshot txDataSnapshot = takeSnapshot(); - // LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, - // txResult, txDataSnapshot); - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txRequest, txResult, null, - operationResultArray(operationResults)); - this.txset.add(tx); - // this.txset.commit(); - - // this.storage.flush(); + dataset.cancel(); + + TransactionStagedSnapshot txDataSnapshot = takeDataSnapshot(); + + LedgerTransactionData tx; + try { + tx = new LedgerTransactionData(blockEditor.getBlockHeight(), txRequest, txResult, txDataSnapshot, + operationResultArray(operationResults)); + this.txset.add(tx); + this.txset.commit(); + } catch (Exception e) { + throw new TransactionRollbackException(e.getMessage(), e); + } - // TODO: 未处理出错时 dataset 和 txset 的内部状态恢复,有可能出现不一致的情况; + try { + this.storage.flush(); + } catch (Exception e) { + throw new BlockRollbackException(e.getMessage(), e); + } // put snapshot into stack; - // TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); - // editor.commitTxSnapshot(snapshot); + TxSnapshot snapshot = new TxSnapshot(txDataSnapshot, txset.getRootHash()); + blockEditor.commitTxSnapshot(snapshot); committed = true; return tx; } - private TransactionStagedSnapshot takeSnapshot() { + private TransactionStagedSnapshot takeDataSnapshot() { TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); txDataSnapshot.setAdminAccountHash(dataset.getAdminAccount().getHash()); txDataSnapshot.setContractAccountSetHash(dataset.getContractAccountSet().getRootHash()); @@ -439,22 +641,22 @@ public class LedgerTransactionalEditor implements LedgerEditor { return; } if (this.committed) { - throw new IllegalStateException("Transaction had been committed!"); + throw new IllegalStateException("This transaction had been committed!"); } - // dataset.cancel(); - // storage.cancel(); + dataset.cancel(); + storage.cancel(); - // editor.rollbackNewTx(); + blockEditor.rollbackCurrentTx(); rollbacked = true; } private void checkTxState() { if (this.committed) { - throw new IllegalStateException("Transaction had been committed!"); + throw new IllegalStateException("This transaction had been committed!"); } if (this.rollbacked) { - throw new IllegalStateException("Transaction had been rollbacked!"); + throw new IllegalStateException("This transaction had been rollbacked!"); } } } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java index b4795c01..aa8fcf93 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/TransactionBatchProcessor.java @@ -8,7 +8,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.BlockRollbackException; import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.ContractDoesNotExistException; +import com.jd.blockchain.ledger.DataAccountDoesNotExistException; +import com.jd.blockchain.ledger.IllegalTransactionException; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerException; import com.jd.blockchain.ledger.Operation; @@ -16,7 +20,9 @@ import com.jd.blockchain.ledger.OperationResult; import com.jd.blockchain.ledger.OperationResultData; import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; +import com.jd.blockchain.ledger.TransactionRollbackException; import com.jd.blockchain.ledger.TransactionState; +import com.jd.blockchain.ledger.UserDoesNotExistException; import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerService; @@ -26,6 +32,7 @@ import com.jd.blockchain.ledger.core.TransactionRequestContext; import com.jd.blockchain.service.TransactionBatchProcess; import com.jd.blockchain.service.TransactionBatchResult; import com.jd.blockchain.service.TransactionBatchResultHandle; +import com.jd.blockchain.transaction.TxResponseMessage; import com.jd.blockchain.utils.Bytes; public class TransactionBatchProcessor implements TransactionBatchProcess { @@ -50,12 +57,9 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { private TransactionBatchResult batchResult; /** - * @param newBlockEditor - * 新区块的数据编辑器; - * @param previousBlockDataset - * 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; - * @param opHandles - * 操作处理对象注册表; + * @param newBlockEditor 新区块的数据编辑器; + * @param previousBlockDataset 新区块的前一个区块的数据集;即未提交新区块之前的经过共识的账本最新数据集; + * @param opHandles 操作处理对象注册表; */ public TransactionBatchProcessor(LedgerEditor newBlockEditor, LedgerDataSet previousBlockDataset, OperationHandleRegisteration opHandles, LedgerService ledgerService) { @@ -74,14 +78,63 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { */ @Override public TransactionResponse schedule(TransactionRequest request) { - // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; - LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); - TransactionState result; + TransactionResponse resp; + try { + LOGGER.debug("Start handling transaction... --[BlockHeight={}][RequestHash={}][TxHash={}]", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); + // 创建交易上下文; + // 此调用将会验证交易签名,验签失败将会抛出异常,同时,不记录签名错误的交易到链上; + LedgerTransactionContext txCtx = newBlockEditor.newTransaction(request); + + // 处理交易; + resp = handleTx(request, txCtx); + + LOGGER.debug("Complete handling transaction. --[BlockHeight={}][RequestHash={}][TxHash={}]", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash()); + + } catch (IllegalTransactionException e) { + // 抛弃发生处理异常的交易请求; + resp = discard(request, e.getTxState()); + LOGGER.error(String.format( + "Ignore transaction caused by IllegalTransactionException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); + + } catch (BlockRollbackException e) { + // 抛弃发生处理异常的交易请求; +// resp = discard(request, TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK); + LOGGER.error(String.format( + "Ignore transaction caused by BlockRollbackException! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); + throw e; + } catch (Exception e) { + // 抛弃发生处理异常的交易请求; + resp = discard(request, TransactionState.SYSTEM_ERROR); + LOGGER.error(String.format( + "Ignore transaction caused by the system exception! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); - List operationResults = new ArrayList<>(); + } - try { + responseList.add(resp); + return resp; + } + /** + * 处理交易;
+ * + * 此方法会处理所有的异常,以不同结果的 {@link TransactionResponse} 返回; + * + * @param request + * @param txCtx + * @return + */ + private TransactionResponse handleTx(TransactionRequest request, LedgerTransactionContext txCtx) { + TransactionState result; + List operationResults = new ArrayList<>(); + try { LedgerDataSet dataset = txCtx.getDataSet(); TransactionRequestContext reqCtx = new TransactionRequestContextImpl(request); // TODO: 验证签名者的有效性; @@ -101,7 +154,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { OperationHandleContext handleContext = new OperationHandleContext() { @Override public void handle(Operation operation) { - //assert; Instance of operation are one of User related operations or DataAccount related operations; + // assert; Instance of operation are one of User related operations or + // DataAccount related operations; OperationHandle hdl = opHandles.getHandle(operation.getClass()); hdl.process(operation, dataset, reqCtx, previousBlockDataset, this, ledgerService); } @@ -110,7 +164,8 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { int opIndex = 0; for (Operation op : ops) { opHandle = opHandles.getHandle(op.getClass()); - BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, ledgerService); + BytesValue opResult = opHandle.process(op, dataset, reqCtx, previousBlockDataset, handleContext, + ledgerService); if (opResult != null) { operationResults.add(new OperationResultData(opIndex, opResult)); } @@ -119,19 +174,46 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { // 提交交易(事务); result = TransactionState.SUCCESS; - txCtx.commit(result, operationResults); + } catch (TransactionRollbackException e) { + result = TransactionState.IGNORED_BY_TX_FULL_ROLLBACK; + txCtx.rollback(); + LOGGER.error(String.format( + "Transaction was full rolled back! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); + } catch (BlockRollbackException e) { + result = TransactionState.IGNORED_BY_BLOCK_FULL_ROLLBACK; + txCtx.rollback(); + LOGGER.error( + String.format("Transaction was rolled back! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), + request.getTransactionContent().getHash(), e.getMessage()), + e); + // 重新抛出由上层错误处理; + throw e; } catch (LedgerException e) { // TODO: 识别更详细的异常类型以及执行对应的处理; result = TransactionState.LEDGER_ERROR; - txCtx.discardAndCommit(TransactionState.LEDGER_ERROR, operationResults); - LOGGER.warn(String.format("Transaction rollback caused by the ledger exception! --[TxHash=%s] --%s", - request.getHash().toBase58(), e.getMessage()), e); + if (e instanceof DataAccountDoesNotExistException) { + result = TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST; + } else if (e instanceof UserDoesNotExistException) { + result = TransactionState.USER_DOES_NOT_EXIST; + } else if (e instanceof ContractDoesNotExistException) { + result = TransactionState.CONTRACT_DOES_NOT_EXIST; + } + txCtx.discardAndCommit(result, operationResults); + LOGGER.error(String.format( + "Due to ledger exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); } catch (Exception e) { result = TransactionState.SYSTEM_ERROR; txCtx.discardAndCommit(TransactionState.SYSTEM_ERROR, operationResults); - LOGGER.warn(String.format("Transaction rollback caused by the system exception! --[TxHash=%s] --%s", - request.getHash().toBase58(), e.getMessage()), e); + LOGGER.error(String.format( + "Due to system exception, the data changes resulting from the transaction will be rolled back and the results of the transaction will be committed! --[BlockHeight=%s][RequestHash=%s][TxHash=%s] --%s", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + e.getMessage()), e); } TxResponseHandle resp = new TxResponseHandle(request, result); @@ -139,9 +221,24 @@ public class TransactionBatchProcessor implements TransactionBatchProcess { OperationResult[] operationResultArray = new OperationResult[operationResults.size()]; resp.setOperationResults(operationResults.toArray(operationResultArray)); } + return resp; + } - responseList.add(resp); - + /** + * 直接丢弃交易; + * + * @param request + * @param txState + * @return 丢弃交易的回复;只包含原始请求中的交易内容哈希和交易被丢弃的原因,而不包含区块信息; + */ + private TransactionResponse discard(TransactionRequest request, TransactionState txState) { + // 丢弃交易的回复;只返回请求的交易内容哈希和交易被丢弃的原因, + TxResponseMessage resp = new TxResponseMessage(request.getTransactionContent().getHash()); + resp.setExecutionState(txState); + + LOGGER.error("Discard transaction request! --[BlockHeight={}][RequestHash={}][TxHash={}][ResponseState={}]", + newBlockEditor.getBlockHeight(), request.getHash(), request.getTransactionContent().getHash(), + resp.getExecutionState()); return resp; } diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java index c07dd628..2745a377 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/DataAccountKVSetOperationHandle.java @@ -4,6 +4,7 @@ import org.springframework.stereotype.Service; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataAccountDoesNotExistException; import com.jd.blockchain.ledger.DataAccountKVSetOperation; import com.jd.blockchain.ledger.DataAccountKVSetOperation.KVWriteEntry; import com.jd.blockchain.ledger.Operation; @@ -26,9 +27,11 @@ public class DataAccountKVSetOperationHandle implements OperationHandle { LedgerDataSet previousBlockDataset, OperationHandleContext handleContext, LedgerService ledgerService) { DataAccountKVSetOperation kvWriteOp = (DataAccountKVSetOperation) op; DataAccount account = dataset.getDataAccountSet().getDataAccount(kvWriteOp.getAccountAddress()); + if (account == null) { + throw new DataAccountDoesNotExistException("DataAccount doesn't exist!"); + } KVWriteEntry[] writeSet = kvWriteOp.getWriteSet(); for (KVWriteEntry kvw : writeSet) { -// byte[] value = BinaryProtocol.encode(kvw.getValue(), BytesValue.class); account.setBytes(Bytes.fromString(kvw.getKey()), kvw.getValue(), kvw.getExpectedVersion()); } return null; diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java index a5b592ab..da4da430 100644 --- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java +++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/JVMContractEventSendOperationHandle.java @@ -1,17 +1,11 @@ package com.jd.blockchain.ledger.core.impl.handles; -import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; - import com.jd.blockchain.contract.engine.ContractCode; import com.jd.blockchain.contract.engine.ContractEngine; import com.jd.blockchain.contract.engine.ContractServiceProviders; -import com.jd.blockchain.ledger.Operation; import com.jd.blockchain.ledger.core.ContractAccount; -import com.jd.blockchain.ledger.core.LedgerDataSet; -import com.jd.blockchain.ledger.core.LedgerService; -import com.jd.blockchain.ledger.core.TransactionRequestContext; -import com.jd.blockchain.ledger.core.impl.OperationHandleContext; -import com.jd.blockchain.utils.concurrent.AsyncFuture; + +import static com.jd.blockchain.utils.BaseConstant.CONTRACT_SERVICE_PROVIDER; public class JVMContractEventSendOperationHandle extends AbtractContractEventHandle { diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java index eab81350..fd9df2d4 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java @@ -1,45 +1,10 @@ package test.com.jd.blockchain.ledger; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Random; - -import org.junit.Test; -import org.mockito.Mockito; - import com.jd.blockchain.binaryproto.BinaryProtocol; import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.HashDigest; -import com.jd.blockchain.ledger.BlockchainKeyGenerator; -import com.jd.blockchain.ledger.BlockchainKeypair; -import com.jd.blockchain.ledger.BytesValue; -import com.jd.blockchain.ledger.BytesData; -import com.jd.blockchain.ledger.EndpointRequest; -import com.jd.blockchain.ledger.LedgerBlock; -import com.jd.blockchain.ledger.LedgerInitSetting; -import com.jd.blockchain.ledger.LedgerTransaction; -import com.jd.blockchain.ledger.NodeRequest; -import com.jd.blockchain.ledger.OperationResult; -import com.jd.blockchain.ledger.TransactionContent; -import com.jd.blockchain.ledger.TransactionContentBody; -import com.jd.blockchain.ledger.TransactionRequest; -import com.jd.blockchain.ledger.TransactionRequestBuilder; -import com.jd.blockchain.ledger.TransactionResponse; -import com.jd.blockchain.ledger.TransactionState; -import com.jd.blockchain.ledger.UserRegisterOperation; -import com.jd.blockchain.ledger.core.LedgerDataSet; -import com.jd.blockchain.ledger.core.LedgerEditor; -import com.jd.blockchain.ledger.core.LedgerRepository; -import com.jd.blockchain.ledger.core.LedgerTransactionContext; -import com.jd.blockchain.ledger.core.UserAccount; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.*; import com.jd.blockchain.ledger.core.impl.DefaultOperationHandleRegisteration; import com.jd.blockchain.ledger.core.impl.LedgerManager; import com.jd.blockchain.ledger.core.impl.LedgerTransactionalEditor; @@ -48,6 +13,15 @@ import com.jd.blockchain.service.TransactionBatchResultHandle; import com.jd.blockchain.storage.service.utils.MemoryKVStorage; import com.jd.blockchain.transaction.TxBuilder; import com.jd.blockchain.utils.Bytes; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.Random; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; public class ContractInvokingTest { static { @@ -184,7 +158,7 @@ public class ContractInvokingTest { // 创建账本; LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys); LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq); LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); @@ -204,10 +178,9 @@ public class ContractInvokingTest { assertEquals(0, block.getHeight()); assertNotNull(block.getHash()); + assertNull(block.getLedgerHash()); assertNull(block.getPreviousHash()); - assertEquals(block.getHash(), block.getLedgerHash()); - // 提交数据,写入存储; ldgEdt.commit(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditorTest.java similarity index 86% rename from source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java rename to source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditorTest.java index c7f3d6e6..0779204e 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditerTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerEditorTest.java @@ -16,6 +16,7 @@ import com.jd.blockchain.crypto.SignatureFunction; import com.jd.blockchain.crypto.service.classic.ClassicAlgorithm; import com.jd.blockchain.crypto.service.classic.ClassicCryptoService; import com.jd.blockchain.crypto.service.sm.SMCryptoService; +import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; import com.jd.blockchain.ledger.BytesValue; import com.jd.blockchain.ledger.DataType; @@ -38,7 +39,7 @@ import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.utils.net.NetworkAddress; -public class LedgerEditerTest { +public class LedgerEditorTest { private static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), SMCryptoService.class.getName() }; @@ -52,6 +53,13 @@ public class LedgerEditerTest { private static final String LEDGER_KEY_PREFIX = "LDG://"; private SignatureFunction signatureFunction; + private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); + + private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 }; + /** * 初始化一个; */ @@ -74,8 +82,8 @@ public class LedgerEditerTest { return LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); } - private LedgerTransactionContext createGenisisTx(LedgerEditor ldgEdt) { - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); + private LedgerTransactionContext createGenisisTx(LedgerEditor ldgEdt, BlockchainKeypair[] partis) { + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partis); LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq); @@ -86,7 +94,7 @@ public class LedgerEditerTest { @Test public void testWriteDataAccoutKvOp() { LedgerEditor ldgEdt = createLedgerInitEditor(); - LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt); + LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants); LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); @@ -119,7 +127,7 @@ public class LedgerEditerTest { @Test public void testGennesisBlockCreation() { LedgerEditor ldgEdt = createLedgerInitEditor(); - LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt); + LedgerTransactionContext genisisTxCtx = createGenisisTx(ldgEdt, participants); LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); AsymmetricKeypair cryptoKeyPair = signatureFunction.generateKeypair(); @@ -130,7 +138,7 @@ public class LedgerEditerTest { LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); - TransactionRequest genesisTxReq = genisisTxCtx.getRequestTX(); + TransactionRequest genesisTxReq = genisisTxCtx.getTransactionRequest(); assertEquals(genesisTxReq.getTransactionContent().getHash(), tx.getTransactionContent().getHash()); assertEquals(0, tx.getBlockHeight()); @@ -138,13 +146,12 @@ public class LedgerEditerTest { assertEquals(0, block.getHeight()); assertNotNull(block.getHash()); + assertNull(block.getLedgerHash()); assertNull(block.getPreviousHash()); - assertEquals(block.getHash(), block.getLedgerHash()); - // 提交数据,写入存储; ldgEdt.commit(); } - + } diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java index 9639602c..dfc17f24 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerManagerTest.java @@ -63,6 +63,13 @@ public class LedgerManagerTest { public static final String[] SUPPORTED_PROVIDERS = { ClassicCryptoService.class.getName(), SMCryptoService.class.getName() }; + private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); + + private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 }; + private SignatureFunction signatureFunction; @Before @@ -83,13 +90,13 @@ public class LedgerManagerTest { LedgerEditor ldgEdt = ledgerManager.newLedger(initSetting, storage); // 创建一个模拟的创世交易; - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(participants); // 记录交易,注册用户; LedgerTransactionContext txCtx = ldgEdt.newTransaction(genesisTxReq); LedgerDataSet ldgDS = txCtx.getDataSet(); BlockchainKeypair userKP = BlockchainKeyGenerator.getInstance().generate(); - + UserAccount userAccount = ldgDS.getUserAccountSet().register(userKP.getAddress(), userKP.getPubKey()); userAccount.setProperty("Name", "孙悟空", -1); userAccount.setProperty("Age", "10000", -1); @@ -109,7 +116,8 @@ public class LedgerManagerTest { assertEquals(0, genesisBlock.getHeight()); assertNotNull(genesisBlock.getHash()); assertNull(genesisBlock.getPreviousHash()); - assertEquals(ledgerHash, genesisBlock.getLedgerHash()); + // 创世区块的账本hash 为null;创世区块本身的哈希就代表了账本的哈希; + assertNull(genesisBlock.getLedgerHash()); // 提交数据,写入存储; ldgEdt.commit(); @@ -124,7 +132,8 @@ public class LedgerManagerTest { LedgerBlock latestBlock = reloadLedgerRepo.getLatestBlock(); assertEquals(0, latestBlock.getHeight()); assertEquals(ledgerHash, latestBlock.getHash()); - assertEquals(ledgerHash, latestBlock.getLedgerHash()); + // 创世区块的账本hash 为null;创世区块本身的哈希就代表了账本的哈希; + assertNull(latestBlock.getLedgerHash()); LedgerEditor editor1 = reloadLedgerRepo.createNextBlock(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java index 3a631ad3..6101cdba 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/LedgerTestUtils.java @@ -24,6 +24,7 @@ import com.jd.blockchain.transaction.ConsensusParticipantData; import com.jd.blockchain.transaction.LedgerInitSettingData; import com.jd.blockchain.transaction.TransactionService; import com.jd.blockchain.transaction.TxBuilder; +import com.jd.blockchain.utils.Bytes; import com.jd.blockchain.utils.io.BytesUtils; import com.jd.blockchain.utils.net.NetworkAddress; @@ -38,10 +39,10 @@ public class LedgerTestUtils { private static Random rand = new Random(); - public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash) { - BlockchainKeypair key = BlockchainKeyGenerator.getInstance().generate(ED25519); - return createTxRequest_UserReg(ledgerHash, key); - } +// public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash) { +// BlockchainKeypair key = BlockchainKeyGenerator.getInstance().generate(ED25519); +// return createTxRequest_UserReg(ledgerHash, key); +// } public static LedgerInitSetting createLedgerInitSetting() { BlockchainKeypair[] partiKeys = new BlockchainKeypair[2]; @@ -81,25 +82,114 @@ public class LedgerTestUtils { return initSetting; } - public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair) { - return createTxRequest_UserReg(ledgerHash, userKeypair, null); +// public static TransactionRequest createTxRequest_UserReg(BlockchainKeypair userKeypair, HashDigest ledgerHash, BlockchainKeypair... partiKeys) { +// return createTxRequest_UserReg(userKeypair, ledgerHash, null, null); +// } + + public static TransactionRequest createLedgerInitTxRequest(BlockchainKeypair... participants) { + TxBuilder txBuilder = new TxBuilder(null); + + for (BlockchainKeypair parti : participants) { + txBuilder.users().register(parti.getIdentity()); + } + + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + for (BlockchainKeypair parti : participants) { + txReqBuilder.signAsNode(parti); + } + + return txReqBuilder.buildRequest(); } - public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair userKeypair, - BlockchainKeypair gatewayKeypair) { +// public static TransactionRequest createTxRequest_UserReg(HashDigest ledgerHash, BlockchainKeypair nodeKeypair, +// BlockchainKeypair... signers) { +// return createTxRequest_UserReg(BlockchainKeyGenerator.getInstance().generate(), ledgerHash, nodeKeypair, +// signers); +// } + + public static TransactionRequest createTxRequest_UserReg(BlockchainKeypair userKeypair, HashDigest ledgerHash, + BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) { TxBuilder txBuilder = new TxBuilder(ledgerHash); txBuilder.users().register(userKeypair.getIdentity()); TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); - txReqBuilder.signAsEndpoint(userKeypair); - if (gatewayKeypair != null) { - txReqBuilder.signAsNode(gatewayKeypair); + if (signers != null) { + for (BlockchainKeypair signer : signers) { + txReqBuilder.signAsEndpoint(signer); + } + } + if (nodeKeypair != null) { + txReqBuilder.signAsNode(nodeKeypair); + } + + return txReqBuilder.buildRequest(); + } + + public static TransactionRequest createTxRequest_DataAccountReg(BlockchainKeypair dataAccountID, HashDigest ledgerHash, + BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) { + TxBuilder txBuilder = new TxBuilder(ledgerHash); + + txBuilder.dataAccounts().register(dataAccountID.getIdentity()); + + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + if (signers != null) { + for (BlockchainKeypair signer : signers) { + txReqBuilder.signAsEndpoint(signer); + } + } + if (nodeKeypair != null) { + txReqBuilder.signAsNode(nodeKeypair); + } + + return txReqBuilder.buildRequest(); + } + + public static TransactionRequest createTxRequest_DataAccountWrite(Bytes dataAccountAddress, String key, String value, long version, HashDigest ledgerHash, + BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) { + TxBuilder txBuilder = new TxBuilder(ledgerHash); + + txBuilder.dataAccount(dataAccountAddress).setText(key, value, version); + + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + if (signers != null) { + for (BlockchainKeypair signer : signers) { + txReqBuilder.signAsEndpoint(signer); + } + } + if (nodeKeypair != null) { + txReqBuilder.signAsNode(nodeKeypair); } return txReqBuilder.buildRequest(); } + /** + * @param userKeypair 要注册的用户key; + * @param ledgerHash 账本哈希; + * @param nodeKeypair 节点key; + * @param signers 签名者列表; + * @return + */ + public static TransactionRequest createTxRequest_MultiOPs_WithNotExistedDataAccount(BlockchainKeypair userKeypair, + HashDigest ledgerHash, BlockchainKeypair nodeKeypair, BlockchainKeypair... signers) { + TxBuilder txBuilder = new TxBuilder(ledgerHash); + + txBuilder.users().register(userKeypair.getIdentity()); + + // 故意构建一个错误的 + BlockchainKeypair testKey = BlockchainKeyGenerator.getInstance().generate(); + txBuilder.dataAccount(testKey.getAddress()).setBytes("AA", "Value".getBytes(), 1); + + TransactionRequestBuilder txReqBuilder = txBuilder.prepareRequest(); + txReqBuilder.signAsEndpoint(nodeKeypair); + if (nodeKeypair != null) { + txReqBuilder.signAsNode(nodeKeypair); + } + + return txReqBuilder.buildRequest(); + } + public static TransactionStagedSnapshot generateRandomSnapshot() { TransactionStagedSnapshot txDataSnapshot = new TransactionStagedSnapshot(); txDataSnapshot.setAdminAccountHash(generateRandomHash()); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/MerkleDataSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/MerkleDataSetTest.java index fbb5eb09..ce571d71 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/MerkleDataSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/MerkleDataSetTest.java @@ -58,6 +58,7 @@ public class MerkleDataSetTest { mds.setValue("C", "C".getBytes(), -1); mds.commit(); + HashDigest root1 = mds.getRootHash(); // 1个KV项的存储KEY的数量= 1 + 1(保存SN) + Merkle节点数量; // 所以:3 项; @@ -68,6 +69,8 @@ public class MerkleDataSetTest { mds.setValue("B", "B".getBytes(), 0); mds.setValue("C", "C".getBytes(), 0); mds.commit(); + HashDigest root2 = mds.getRootHash(); + assertNotEquals(root1, root2); // Version changed only;仅仅增加 merkle 节点,此时 Merkle 树只有 1 层路径节点,因此只更新2个数据节点和 1 // 个路径节点;(注:版本值是在同一个 key 下按序列保存的); @@ -76,6 +79,9 @@ public class MerkleDataSetTest { mds.setValue("D", "DValue".getBytes(), -1); mds.commit(); + HashDigest root3 = mds.getRootHash(); + assertNotEquals(root2, root3); + assertNotEquals(root1, root3); // New key added, include 1 versioning kv, 1 sn key, 2 merkle nodes; // String[] keys = StringUtils.toStringArray(storage.keySet()); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java index 72c8a848..f857a6ad 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionBatchProcessorTest.java @@ -1,6 +1,7 @@ package test.com.jd.blockchain.ledger; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -11,6 +12,8 @@ import com.jd.blockchain.binaryproto.DataContractRegistry; import com.jd.blockchain.crypto.HashDigest; import com.jd.blockchain.ledger.BlockchainKeyGenerator; import com.jd.blockchain.ledger.BlockchainKeypair; +import com.jd.blockchain.ledger.BytesValue; +import com.jd.blockchain.ledger.DataAccountRegisterOperation; import com.jd.blockchain.ledger.EndpointRequest; import com.jd.blockchain.ledger.LedgerBlock; import com.jd.blockchain.ledger.LedgerInitSetting; @@ -22,6 +25,7 @@ import com.jd.blockchain.ledger.TransactionRequest; import com.jd.blockchain.ledger.TransactionResponse; import com.jd.blockchain.ledger.TransactionState; import com.jd.blockchain.ledger.UserRegisterOperation; +import com.jd.blockchain.ledger.core.DataAccount; import com.jd.blockchain.ledger.core.LedgerDataSet; import com.jd.blockchain.ledger.core.LedgerEditor; import com.jd.blockchain.ledger.core.LedgerRepository; @@ -43,6 +47,7 @@ public class TransactionBatchProcessorTest { DataContractRegistry.register(EndpointRequest.class); DataContractRegistry.register(TransactionResponse.class); DataContractRegistry.register(UserRegisterOperation.class); + DataContractRegistry.register(DataAccountRegisterOperation.class); } private static final String LEDGER_KEY_PREFIX = "LDG://"; @@ -54,19 +59,20 @@ public class TransactionBatchProcessorTest { private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); - private TransactionRequest transactionRequest; + private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 }; - // 采用基于内存的 Storage; - private MemoryKVStorage storage = new MemoryKVStorage(); + // TODO: 验证无效签名会被拒绝; @Test - public void testTxReqProcess() { + public void testSingleTxProcess() { + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + // 初始化账本到指定的存储库; - ledgerHash = initLedger(storage, parti0, parti1, parti2, parti3); + ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3); // 加载账本; LedgerManager ledgerManager = new LedgerManager(); - LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, storage); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); // 验证参与方账户的存在; LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); @@ -84,19 +90,283 @@ public class TransactionBatchProcessorTest { // 注册新用户; BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); - transactionRequest = LedgerTestUtils.createTxRequest_UserReg(ledgerHash, userKeypair, parti0); - txbatchProcessor.schedule(transactionRequest); + TransactionRequest transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair, ledgerHash, parti0, + parti0); + TransactionResponse txResp = txbatchProcessor.schedule(transactionRequest); + + LedgerBlock newBlock = newBlockEditor.prepare(); + newBlockEditor.commit(); + + // 验证正确性; + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); + + LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); + assertEquals(newBlock.getHash(), latestBlock.getHash()); + assertEquals(1, newBlock.getHeight()); + + assertEquals(TransactionState.SUCCESS, txResp.getExecutionState()); + } + + @Test + public void testMultiTxsProcess() { + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + // 初始化账本到指定的存储库; + ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3); + + // 加载账本; + LedgerManager ledgerManager = new LedgerManager(); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); + + // 验证参与方账户的存在; + LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); + UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress()); + assertNotNull(user0); + boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress()); + assertTrue(partiRegistered); + + // 生成新区块; + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, + opReg, ledgerManager); + + // 注册新用户; + BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, + parti0, parti0); + TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest1); + + BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest2 = LedgerTestUtils.createTxRequest_UserReg(userKeypair2, ledgerHash, + parti0, parti0); + TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest2); LedgerBlock newBlock = newBlockEditor.prepare(); newBlockEditor.commit(); + assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState()); + assertEquals(TransactionState.SUCCESS, txResp2.getExecutionState()); + // 验证正确性; ledgerManager = new LedgerManager(); - ledgerRepo = ledgerManager.register(ledgerHash, storage); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); assertEquals(newBlock.getHash(), latestBlock.getHash()); assertEquals(1, newBlock.getHeight()); + + LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock); + boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress()); + boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress()); + assertTrue(existUser1); + assertTrue(existUser2); + } + + @Test + public void testTxRollback() { + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + // 初始化账本到指定的存储库; + ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3); + + // 加载账本; + LedgerManager ledgerManager = new LedgerManager(); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); + + // 验证参与方账户的存在; + LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); + UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress()); + assertNotNull(user0); + boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress()); + assertTrue(partiRegistered); + + // 生成新区块; + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, + opReg, ledgerManager); + + // 注册新用户; + BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, + parti0, parti0); + TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest1); + + BlockchainKeypair userKeypair2 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest2 = LedgerTestUtils + .createTxRequest_MultiOPs_WithNotExistedDataAccount(userKeypair2, ledgerHash, parti0, parti0); + TransactionResponse txResp2 = txbatchProcessor.schedule(transactionRequest2); + + BlockchainKeypair userKeypair3 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest3 = LedgerTestUtils.createTxRequest_UserReg(userKeypair3, ledgerHash, + parti0, parti0); + TransactionResponse txResp3 = txbatchProcessor.schedule(transactionRequest3); + + LedgerBlock newBlock = newBlockEditor.prepare(); + newBlockEditor.commit(); + + assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState()); + assertEquals(TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST, txResp2.getExecutionState()); + assertEquals(TransactionState.SUCCESS, txResp3.getExecutionState()); + + // 验证正确性; + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); + + LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); + assertEquals(newBlock.getHash(), latestBlock.getHash()); + assertEquals(1, newBlock.getHeight()); + + LedgerTransaction tx1 = ledgerRepo.getTransactionSet() + .get(transactionRequest1.getTransactionContent().getHash()); + LedgerTransaction tx2 = ledgerRepo.getTransactionSet() + .get(transactionRequest2.getTransactionContent().getHash()); + LedgerTransaction tx3 = ledgerRepo.getTransactionSet() + .get(transactionRequest3.getTransactionContent().getHash()); + + assertNotNull(tx1); + assertEquals(TransactionState.SUCCESS, tx1.getExecutionState()); + assertNotNull(tx2); + assertEquals(TransactionState.DATA_ACCOUNT_DOES_NOT_EXIST, tx2.getExecutionState()); + assertNotNull(tx3); + assertEquals(TransactionState.SUCCESS, tx3.getExecutionState()); + + LedgerDataSet ledgerDS = ledgerRepo.getDataSet(latestBlock); + boolean existUser1 = ledgerDS.getUserAccountSet().contains(userKeypair1.getAddress()); + boolean existUser2 = ledgerDS.getUserAccountSet().contains(userKeypair2.getAddress()); + boolean existUser3 = ledgerDS.getUserAccountSet().contains(userKeypair3.getAddress()); + assertTrue(existUser1); + assertFalse(existUser2); + assertTrue(existUser3); + } + + @Test + public void testTxRollbackByVersionsConfliction() { + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + // 初始化账本到指定的存储库; + ledgerHash = initLedger(STORAGE, parti0, parti1, parti2, parti3); + + // 加载账本; + LedgerManager ledgerManager = new LedgerManager(); + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); + + // 验证参与方账户的存在; + LedgerDataSet previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); + UserAccount user0 = previousBlockDataset.getUserAccountSet().getUser(parti0.getAddress()); + assertNotNull(user0); + boolean partiRegistered = previousBlockDataset.getUserAccountSet().contains(parti0.getAddress()); + assertTrue(partiRegistered); + + // 注册数据账户; + // 生成新区块; + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, + opReg, ledgerManager); + + BlockchainKeypair dataAccountKeypair = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_DataAccountReg(dataAccountKeypair, + ledgerHash, parti0, parti0); + TransactionResponse txResp1 = txbatchProcessor.schedule(transactionRequest1); + LedgerBlock newBlock = newBlockEditor.prepare(); + newBlockEditor.commit(); + + assertEquals(TransactionState.SUCCESS, txResp1.getExecutionState()); + DataAccount dataAccount = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()); + assertNotNull(dataAccount); + + // 正确写入 KV 数据; + TransactionRequest txreq1 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K1", "V-1-1", -1, ledgerHash, parti0, parti0); + TransactionRequest txreq2 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K2", "V-2-1", -1, ledgerHash, parti0, parti0); + TransactionRequest txreq3 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K3", "V-3-1", -1, ledgerHash, parti0, parti0); + TransactionRequest txreq4 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K1", "V-1-2", 0, ledgerHash, parti0, parti0); + + newBlockEditor = ledgerRepo.createNextBlock(); + previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); + txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); + + txbatchProcessor.schedule(txreq1); + txbatchProcessor.schedule(txreq2); + txbatchProcessor.schedule(txreq3); + txbatchProcessor.schedule(txreq4); + + newBlock = newBlockEditor.prepare(); + newBlockEditor.commit(); + + BytesValue v1_0 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1", + 0); + BytesValue v1_1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1", + 1); + BytesValue v2 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K2", + 0); + BytesValue v3 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K3", + 0); + + assertNotNull(v1_0); + assertNotNull(v1_1); + assertNotNull(v2); + assertNotNull(v3); + + assertEquals("V-1-1", v1_0.getValue().toUTF8String()); + assertEquals("V-1-2", v1_1.getValue().toUTF8String()); + assertEquals("V-2-1", v2.getValue().toUTF8String()); + assertEquals("V-3-1", v3.getValue().toUTF8String()); + + // 提交多笔数据写入的交易,包含存在数据版本冲突的交易,验证交易是否正确回滚; + + TransactionRequest txreq5 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K3", "V-3-2", 0, ledgerHash, parti0, parti0); + // 指定冲突的版本号,正确的应该是版本1; + TransactionRequest txreq6 = LedgerTestUtils.createTxRequest_DataAccountWrite(dataAccountKeypair.getAddress(), + "K1", "V-1-3", 0, ledgerHash, parti0, parti0); + + newBlockEditor = ledgerRepo.createNextBlock(); + previousBlockDataset = ledgerRepo.getDataSet(ledgerRepo.getLatestBlock()); + txbatchProcessor = new TransactionBatchProcessor(newBlockEditor, previousBlockDataset, opReg, ledgerManager); + + txbatchProcessor.schedule(txreq5); + txbatchProcessor.schedule(txreq6); + + newBlock = newBlockEditor.prepare(); + newBlockEditor.commit(); + + BytesValue v1 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K1"); + v3 = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getBytes("K3"); + + long k1_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K1"); + assertEquals(1, k1_version); + long k3_version = ledgerRepo.getDataAccountSet().getDataAccount(dataAccountKeypair.getAddress()).getDataVersion("K3"); + assertEquals(1, k3_version); + + assertNotNull(v1); + assertNotNull(v3); + assertEquals("V-1-2", v1.getValue().toUTF8String()); + assertEquals("V-3-2", v3.getValue().toUTF8String()); + +// // 验证正确性; +// ledgerManager = new LedgerManager(); +// ledgerRepo = ledgerManager.register(ledgerHash, STORAGE); +// +// LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); +// assertEquals(newBlock.getHash(), latestBlock.getHash()); +// assertEquals(1, newBlock.getHeight()); +// +// LedgerTransaction tx1 = ledgerRepo.getTransactionSet() +// .get(transactionRequest1.getTransactionContent().getHash()); +// +// assertNotNull(tx1); +// assertEquals(TransactionState.SUCCESS, tx1.getExecutionState()); + } private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { @@ -106,7 +376,7 @@ public class TransactionBatchProcessorTest { // 创建账本; LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); - TransactionRequest genesisTxReq = LedgerTestUtils.createTxRequest_UserReg(null); + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys); LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq); LedgerDataSet ldgDS = genisisTxCtx.getDataSet(); @@ -128,7 +398,9 @@ public class TransactionBatchProcessorTest { assertNotNull(block.getHash()); assertNull(block.getPreviousHash()); - assertEquals(block.getHash(), block.getLedgerHash()); + // 创世区块的账本哈希为 null; + assertNull(block.getLedgerHash()); + assertNotNull(block.getHash()); // 提交数据,写入存储; ldgEdt.commit(); diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java index a4b719a7..f023a987 100644 --- a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/TransactionSetTest.java @@ -102,8 +102,7 @@ public class TransactionSetTest { txSnapshot.setContractAccountSetHash(contractAccountSetHash); long blockHeight = 8922L; - LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot, - null); + LedgerTransactionData tx = new LedgerTransactionData(blockHeight, txReq, TransactionState.SUCCESS, txSnapshot); txset.add(tx); assertTrue(txset.isUpdated()); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockBody.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockBody.java index ff8f3705..7c82b214 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockBody.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockBody.java @@ -20,4 +20,7 @@ public interface BlockBody extends LedgerDataSnapshot{ @DataField(order=5, primitiveType = PrimitiveType.BYTES) HashDigest getTransactionSetHash(); + + @DataField(order=6, primitiveType = PrimitiveType.INT64) + long getTimestamp(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockRollbackException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockRollbackException.java new file mode 100644 index 00000000..c64f9e42 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/BlockRollbackException.java @@ -0,0 +1,33 @@ +package com.jd.blockchain.ledger; + +public class BlockRollbackException extends LedgerException { + + private static final long serialVersionUID = 3583192000738807503L; + + private TransactionState state; + + public BlockRollbackException(String message) { + this(TransactionState.SYSTEM_ERROR, message); + } + + public BlockRollbackException(TransactionState state, String message) { + super(message); + assert TransactionState.SUCCESS != state; + this.state = state; + } + + public BlockRollbackException(String message, Throwable cause) { + this(TransactionState.SYSTEM_ERROR, message, cause); + } + + public BlockRollbackException(TransactionState state, String message, Throwable cause) { + super(message, cause); + assert TransactionState.SUCCESS != state; + this.state = state; + } + + public TransactionState getState() { + return state; + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractDoesNotExistException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractDoesNotExistException.java new file mode 100644 index 00000000..687ef762 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractDoesNotExistException.java @@ -0,0 +1,16 @@ +package com.jd.blockchain.ledger; + +public class ContractDoesNotExistException extends LedgerException { + + + private static final long serialVersionUID = 8685914012112243771L; + + public ContractDoesNotExistException(String message) { + super(message); + } + + public ContractDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountDoesNotExistException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountDoesNotExistException.java new file mode 100644 index 00000000..428efffc --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/DataAccountDoesNotExistException.java @@ -0,0 +1,16 @@ +package com.jd.blockchain.ledger; + +public class DataAccountDoesNotExistException extends LedgerException { + + + private static final long serialVersionUID = -1889587937401974215L; + + public DataAccountDoesNotExistException(String message) { + super(message); + } + + public DataAccountDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/IllegalTransactionException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/IllegalTransactionException.java new file mode 100644 index 00000000..5a2bb5a1 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/IllegalTransactionException.java @@ -0,0 +1,35 @@ +package com.jd.blockchain.ledger; + +public class IllegalTransactionException extends RuntimeException { + + private static final long serialVersionUID = 6348921847690512944L; + + private TransactionState txState; + + public IllegalTransactionException(String message) { + super(message); + this.txState = TransactionState.SYSTEM_ERROR; + } + + public IllegalTransactionException(String message, TransactionState txState) { + super(message); + assert TransactionState.SUCCESS != txState; + this.txState = txState; + } + + public IllegalTransactionException(String message, Throwable cause) { + super(message, cause); + this.txState = TransactionState.SYSTEM_ERROR; + } + + public IllegalTransactionException(String message, Throwable cause, TransactionState txState) { + super(message, cause); + assert TransactionState.SUCCESS != txState; + this.txState = txState; + } + + public TransactionState getTxState() { + return txState; + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerException.java index 9d0dd838..d0edef01 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerException.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/LedgerException.java @@ -3,6 +3,8 @@ package com.jd.blockchain.ledger; public class LedgerException extends RuntimeException { private static final long serialVersionUID = -4090881296855827888L; + + public LedgerException(String message) { super(message); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionContentBody.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionContentBody.java index 5ffa8739..0c227ab5 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionContentBody.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionContentBody.java @@ -40,6 +40,6 @@ public interface TransactionContentBody { * @return */ @DataField(order = 3, primitiveType = PrimitiveType.INT64) - long getTime(); + long getTimestamp(); } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionException.java deleted file mode 100644 index c88f0792..00000000 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionException.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.jd.blockchain.ledger; - -public class TransactionException extends Exception { - - private static final long serialVersionUID = 3583192000738807503L; - - private TransactionState state; - - public TransactionException(TransactionState state) { - this.state = state; - } - - public TransactionException(TransactionState state, String message) { - super(message); - this.state = state; - } - - public TransactionState getState() { - return state; - } - -} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRollbackException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRollbackException.java new file mode 100644 index 00000000..7694d898 --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/TransactionRollbackException.java @@ -0,0 +1,16 @@ +package com.jd.blockchain.ledger; + +public class TransactionRollbackException extends RuntimeException { + + + private static final long serialVersionUID = -1223140447229570029L; + + public TransactionRollbackException(String message) { + super(message); + } + + public TransactionRollbackException(String message, Throwable cause) { + super(message, cause); + } + +} 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 e89d41b6..6955eb94 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 @@ -11,7 +11,7 @@ import com.jd.blockchain.consts.DataCodes; * @author huanghaiquan * */ -@EnumContract(code= DataCodes.ENUM_TYPE_TRANSACTION_STATE) +@EnumContract(code = DataCodes.ENUM_TYPE_TRANSACTION_STATE) public enum TransactionState { /** @@ -20,19 +20,58 @@ public enum TransactionState { SUCCESS((byte) 0), /** - * 共识错误; + * 账本错误; */ - CONSENSUS_ERROR((byte) 1), - + LEDGER_ERROR((byte) 0x01), + /** - * 账本错误; + * 数据账户不存在; + */ + DATA_ACCOUNT_DOES_NOT_EXIST((byte) 0x02), + + /** + * 用户不存在; + */ + USER_DOES_NOT_EXIST((byte) 0x03), + + /** + * 合约不存在; + */ + CONTRACT_DOES_NOT_EXIST((byte) 0x04), + + /** + * 由于在错误的账本上执行交易而被丢弃; */ - LEDGER_ERROR((byte) 2), + IGNORED_BY_WRONG_LEDGER((byte) 0x40), /** - * 数据序列更新错误; + * 由于交易内容的验签失败而丢弃; */ - DATA_SEQUENCE_UPDATE_ERROR((byte) 3), + IGNORED_BY_WRONG_CONTENT_SIGNATURE((byte) 0x41), + + /** + * 由于交易内容的验签失败而丢弃; + */ + IGNORED_BY_CONFLICTING_STATE((byte) 0x42), + + /** + * 由于交易的整体回滚而丢弃; + *

+ * + * 注: “整体回滚”是指把交易引入的数据更改以及交易记录本身全部都回滚;
+ * “部分回滚”是指把交易引入的数据更改回滚了,但是交易记录本身以及相应的“交易结果({@link TransactionState})”都会提交;
+ */ + IGNORED_BY_TX_FULL_ROLLBACK((byte) 0x43), + + /** + * 由于区块的整体回滚而丢弃; + *

+ * + * 注: “整体回滚”是指把交易引入的数据更改以及交易记录本身全部都回滚;
+ * + * “部分回滚”是指把交易引入的数据更改回滚了,但是交易记录本身以及相应的“交易结果({@link TransactionState})”都会提交;
+ */ + IGNORED_BY_BLOCK_FULL_ROLLBACK((byte) 0x44), /** * 系统错误; @@ -42,9 +81,14 @@ public enum TransactionState { /** * 超时; */ - TIMEOUT((byte) 0x81); + TIMEOUT((byte) 0x81), + + /** + * 共识错误; + */ + CONSENSUS_ERROR((byte) 0x82); - @EnumField(type= PrimitiveType.INT8) + @EnumField(type = PrimitiveType.INT8) public final byte CODE; private TransactionState(byte code) { diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserDoesNotExistException.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserDoesNotExistException.java new file mode 100644 index 00000000..1775405f --- /dev/null +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/UserDoesNotExistException.java @@ -0,0 +1,15 @@ +package com.jd.blockchain.ledger; + +public class UserDoesNotExistException extends LedgerException { + + private static final long serialVersionUID = 397450363050148898L; + + public UserDoesNotExistException(String message) { + super(message); + } + + public UserDoesNotExistException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java index 35e09d78..1ff23a2f 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxBuilder.java @@ -55,12 +55,22 @@ public class TxBuilder implements TransactionBuilder { txContent.addOperations(opFactory.getOperations()); txContent.setTime(time); - byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class); - HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes); + HashDigest contentHash = computeTxContentHash(txContent); txContent.setHash(contentHash); return txContent; } + + public static HashDigest computeTxContentHash(TransactionContent txContent) { + byte[] contentBodyBytes = BinaryProtocol.encode(txContent, TransactionContentBody.class); + HashDigest contentHash = Crypto.getHashFunction(DEFAULT_HASH_ALGORITHM).hash(contentBodyBytes); + return contentHash; + } + + public static boolean verifyTxContentHash(TransactionContent txContent, HashDigest verifiedHash) { + HashDigest hash = computeTxContentHash(txContent); + return hash.equals(verifiedHash); + } public Collection getReturnValuehandlers() { return opFactory.getReturnValuetHandlers(); diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxContentBlob.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxContentBlob.java index c03f1cc7..7413a5ff 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxContentBlob.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxContentBlob.java @@ -84,7 +84,7 @@ public class TxContentBlob implements TransactionContent { } @Override - public long getTime() { + public long getTimestamp() { return time; } diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java index 7d6701a5..87326bb1 100644 --- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java +++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/TxRequestBuilder.java @@ -75,8 +75,14 @@ public class TxRequestBuilder implements TransactionRequestBuilder { } public static boolean verifySignature(TransactionContent txContent, SignatureDigest signDigest, PubKey pubKey) { - return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey, - txContent.getHash().toBytes()); + if (!TxBuilder.verifyTxContentHash(txContent, txContent.getHash())) { + return false; + } + return verifyHashSignature(txContent.getHash(), signDigest, pubKey); + } + + public static boolean verifyHashSignature(HashDigest hash, SignatureDigest signDigest, PubKey pubKey) { + return Crypto.getSignatureFunction(pubKey.getAlgorithm()).verify(signDigest, pubKey, hash.toBytes()); } @Override diff --git a/source/ledger/ledger-rpc/pom.xml b/source/ledger/ledger-rpc/pom.xml index fced7ce8..765c837c 100644 --- a/source/ledger/ledger-rpc/pom.xml +++ b/source/ledger/ledger-rpc/pom.xml @@ -36,16 +36,16 @@ - - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - true - - - - + + + + + + + + + + + + \ No newline at end of file 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 53f5b36e..341136b0 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,505 +1,506 @@ -package com.jd.blockchain.peer.web; - -import java.util.ArrayList; -import java.util.List; - -import com.jd.blockchain.ledger.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -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 com.jd.blockchain.contract.ContractException; -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; - -@RestController -@RequestMapping(path = "/") -public class LedgerQueryController implements BlockchainQueryService { - - @Autowired - private LedgerService ledgerService; - - @RequestMapping(method = RequestMethod.GET, path = "ledgers") - @Override - public HashDigest[] getLedgerHashs() { - return ledgerService.getLedgerHashs(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}") - @Override - public LedgerInfo getLedger(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher - // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; - LedgerInfo ledgerInfo = new LedgerInfo(); - ledgerInfo.setHash(ledgerHash); - ledgerInfo.setLatestBlockHash(ledger.getLatestBlockHash()); - ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); - return ledgerInfo; - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/participants") - @Override - public ParticipantNode[] getConsensusParticipants(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerAdministration ledgerAdministration = ledger.getAdminInfo(); - long participantCount = ledgerAdministration.getParticipantCount(); - if (participantCount <= 0) { - return null; - } - ParticipantNode[] participantNodes = ledgerAdministration.getParticipants(); - // 重新封装,处理Proxy的问题 - if (participantNodes != null && participantNodes.length > 0) { - ParticipantNode[] convertNodes = new ParticipantNode[participantNodes.length]; - for (int i = 0, length = participantNodes.length; i < length; i++) { - convertNodes[i] = new ParticipantCertData(participantNodes[i]); - } - return convertNodes; - } - return null; - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/metadata") - @Override - public LedgerMetadata getLedgerMetadata(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerAdministration ledgerAdministration = ledger.getAdminInfo(); - LedgerMetadata ledgerMetadata = ledgerAdministration.getMetadata(); - return ledgerMetadata; - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}") - @Override - public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long blockHeight) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher - // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; - return ledger.getBlock(blockHeight); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}") - @Override - public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher - // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; - return ledger.getBlock(blockHash); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/txs/count") - @Override - public long getTransactionCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long blockHeight) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHeight); - TransactionSet txSet = ledger.getTransactionSet(block); - return txSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/txs/count") - @Override - public long getTransactionCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - TransactionSet txSet = ledger.getTransactionSet(block); - return txSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/count") - @Override - public long getTransactionTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txSet = ledger.getTransactionSet(block); - return txSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/accounts/count") - @Override - public long getDataAccountCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/accounts/count") - @Override - public long getDataAccountCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/count") - @Override - public long getDataAccountTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/users/count") - @Override - public long getUserCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/users/count") - @Override - public long getUserCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users/count") - @Override - public long getUserTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/contracts/count") - @Override - public long getContractCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long height) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(height); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/contracts/count") - @Override - public long getContractCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getBlock(blockHash); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/count") - @Override - public long getContractTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/txs") - @Override - public LedgerTransaction[] getTransactions(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHeight") long blockHeight, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock ledgerBlock = ledger.getBlock(blockHeight); - TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); - int lastHeightTxTotalNums = 0; - - if (blockHeight > 0) { - lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(blockHeight - 1)).getTotalCount(); - } - - int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(blockHeight)).getTotalCount(); - // 取当前高度的增量交易数,在增量交易里进行查找 - int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; - -// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { -// fromIndex = 0; -// } -// if (count == -1) { -// fromIndex = 0; -// count = currentHeightTxNums; -// } -// if (count > currentHeightTxNums) { -// count = currentHeightTxNums - fromIndex; -// } - int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); - return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/txs") - @Override - public LedgerTransaction[] getTransactions(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "blockHash") HashDigest blockHash, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock ledgerBlock = ledger.getBlock(blockHash); - long height = ledgerBlock.getHeight(); - TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); - int lastHeightTxTotalNums = 0; - - if (height > 0) { - lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); - } - - int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); - // 取当前块hash的增量交易数,在增量交易里进行查找 - int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; - -// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { -// fromIndex = 0; -// } -// if (count == -1) { -// fromIndex = 0; -// count = currentHeightTxNums; -// } -// if (count > currentHeightTxNums) { -// count = currentHeightTxNums - fromIndex; -// } - int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); - return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/{contentHash}") - @Override - public LedgerTransaction getTransactionByContentHash(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "contentHash") HashDigest contentHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.get(contentHash); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/state/{contentHash}") - @Override - public TransactionState getTransactionStateByContentHash(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "contentHash") HashDigest contentHash) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - TransactionSet txset = ledger.getTransactionSet(block); - return txset.getTxState(contentHash); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users/address/{address}") - @Override - public UserInfo getUser(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - return userAccountSet.getUser(address); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") - @Override - public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - } - - @RequestMapping(method = { RequestMethod.GET, - RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") - @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { - if (keys == null || keys.length == 0) { - return null; - } - 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; - for (int i = 0; i < entries.length; i++) { - ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); - if (ver < 0) { - entries[i] = new KVDataObject(keys[i], -1, null); - } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); - } - } - - 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, 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, null); - } else { - BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); - entries[i] = new KVDataObject(keys[i], ver, value); - } - } - } - - return entries; - } - - @RequestMapping(method = { RequestMethod.GET, - RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") - @Override - public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - - return dataAccount.getDataEntries(fromIndex, count); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") - @Override - public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { - - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); - - return dataAccount.getDataEntriesTotalCount(); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") - @Override - public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @PathVariable(name = "address") String address) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - return contractAccountSet.getContract(Bytes.fromBase58(address)); - } - - /** - * get more users by fromIndex and count; - * - * @param ledgerHash - * @param fromIndex - * @param count - * @return - */ - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") - @Override - public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - UserAccountSet userAccountSet = ledger.getUserAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); - return userAccountSet.getAccounts(pages[0], pages[1]); - } - - /** - * get more dataAccounts by fromIndex and count; - * - * @param ledgerHash - * @param fromIndex - * @param count - * @return - */ - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") - @Override - public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); - return dataAccountSet.getAccounts(pages[0], pages[1]); - } - - @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") - @Override - public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, - @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, - @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { - LedgerRepository ledger = ledgerService.getLedger(ledgerHash); - LedgerBlock block = ledger.getLatestBlock(); - ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); - int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); - return contractAccountSet.getAccounts(pages[0], pages[1]); - } - -} +package com.jd.blockchain.peer.web; + +import java.util.ArrayList; +import java.util.List; + +import com.jd.blockchain.ledger.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +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 com.jd.blockchain.contract.ContractException; +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; + +@RestController +@RequestMapping(path = "/") +public class LedgerQueryController implements BlockchainQueryService { + + @Autowired + private LedgerService ledgerService; + + @RequestMapping(method = RequestMethod.GET, path = "ledgers") + @Override + public HashDigest[] getLedgerHashs() { + return ledgerService.getLedgerHashs(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}") + @Override + public LedgerInfo getLedger(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher + // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; + LedgerInfo ledgerInfo = new LedgerInfo(); + ledgerInfo.setHash(ledgerHash); + ledgerInfo.setLatestBlockHash(ledger.getLatestBlockHash()); + ledgerInfo.setLatestBlockHeight(ledger.getLatestBlockHeight()); + return ledgerInfo; + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/participants") + @Override + public ParticipantNode[] getConsensusParticipants(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerAdministration ledgerAdministration = ledger.getAdminInfo(); + long participantCount = ledgerAdministration.getParticipantCount(); + if (participantCount <= 0) { + return null; + } + ParticipantNode[] participantNodes = ledgerAdministration.getParticipants(); + // 重新封装,处理Proxy的问题 + if (participantNodes != null && participantNodes.length > 0) { + ParticipantNode[] convertNodes = new ParticipantNode[participantNodes.length]; + for (int i = 0, length = participantNodes.length; i < length; i++) { + convertNodes[i] = new ParticipantCertData(participantNodes[i]); + } + return convertNodes; + } + return null; + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/metadata") + @Override + public LedgerMetadata getLedgerMetadata(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerAdministration ledgerAdministration = ledger.getAdminInfo(); + LedgerMetadata ledgerMetadata = ledgerAdministration.getMetadata(); + return ledgerMetadata; + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}") + @Override + public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long blockHeight) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher + // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; + return ledger.getBlock(blockHeight); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}") + @Override + public LedgerBlock getBlock(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + // TODO: 需要配置返回值的 spring MsgQueueMessageDispatcher + // ,对返回对象仅仅序列化声明的返回值类型的属性,而不是整个对象本身; + return ledger.getBlock(blockHash); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/txs/count") + @Override + public long getTransactionCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long blockHeight) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHeight); + TransactionSet txSet = ledger.getTransactionSet(block); + return txSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/txs/count") + @Override + public long getTransactionCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + TransactionSet txSet = ledger.getTransactionSet(block); + return txSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/count") + @Override + public long getTransactionTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txSet = ledger.getTransactionSet(block); + return txSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/accounts/count") + @Override + public long getDataAccountCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/accounts/count") + @Override + public long getDataAccountCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/count") + @Override + public long getDataAccountTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/users/count") + @Override + public long getUserCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/users/count") + @Override + public long getUserCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users/count") + @Override + public long getUserTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/contracts/count") + @Override + public long getContractCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long height) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(height); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/contracts/count") + @Override + public long getContractCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getBlock(blockHash); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/count") + @Override + public long getContractTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/height/{blockHeight}/txs") + @Override + public LedgerTransaction[] getTransactions(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHeight") long blockHeight, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock ledgerBlock = ledger.getBlock(blockHeight); + TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); + int lastHeightTxTotalNums = 0; + + if (blockHeight > 0) { + lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(blockHeight - 1)).getTotalCount(); + } + + int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(blockHeight)).getTotalCount(); + // 取当前高度的增量交易数,在增量交易里进行查找 + int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; + +// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { +// fromIndex = 0; +// } +// if (count == -1) { +// fromIndex = 0; +// count = currentHeightTxNums; +// } +// if (count > currentHeightTxNums) { +// count = currentHeightTxNums - fromIndex; +// } + int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); + return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/hash/{blockHash}/txs") + @Override + public LedgerTransaction[] getTransactions(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "blockHash") HashDigest blockHash, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock ledgerBlock = ledger.getBlock(blockHash); + long height = ledgerBlock.getHeight(); + TransactionSet transactionSet = ledger.getTransactionSet(ledgerBlock); + int lastHeightTxTotalNums = 0; + + if (height > 0) { + lastHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height - 1)).getTotalCount(); + } + + int currentHeightTxTotalNums = (int) ledger.getTransactionSet(ledger.getBlock(height)).getTotalCount(); + // 取当前块hash的增量交易数,在增量交易里进行查找 + int currentHeightTxNums = currentHeightTxTotalNums - lastHeightTxTotalNums; + +// if (fromIndex < 0 || fromIndex >= currentHeightTxNums) { +// fromIndex = 0; +// } +// if (count == -1) { +// fromIndex = 0; +// count = currentHeightTxNums; +// } +// if (count > currentHeightTxNums) { +// count = currentHeightTxNums - fromIndex; +// } + int indexAndCount[] = QueryUtil.calFromIndexAndCount(fromIndex, count, currentHeightTxNums); + return transactionSet.getTxs(lastHeightTxTotalNums + indexAndCount[0], indexAndCount[1]); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/{contentHash}") + @Override + public LedgerTransaction getTransactionByContentHash(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "contentHash") HashDigest contentHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.get(contentHash); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/txs/state/{contentHash}") + @Override + public TransactionState getTransactionStateByContentHash(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "contentHash") HashDigest contentHash) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + TransactionSet txset = ledger.getTransactionSet(block); + return txset.getTxState(contentHash); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users/address/{address}") + @Override + public UserInfo getUser(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + return userAccountSet.getUser(address); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}") + @Override + public AccountHeader getDataAccount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + return dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + } + + @RequestMapping(method = { RequestMethod.GET, + RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/{address}/entries") + @Override + public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address, @RequestParam("keys") String... keys) { + if (keys == null || keys.length == 0) { + return null; + } + 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; + for (int i = 0; i < entries.length; i++) { + ver = dataAccount.getDataVersion(Bytes.fromString(keys[i])); + if (ver < 0) { + entries[i] = new KVDataObject(keys[i], -1, null); + } else { + BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); + entries[i] = new KVDataObject(keys[i], ver, value); + } + } + + 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, 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, null); + } else { + BytesValue value = dataAccount.getBytes(Bytes.fromString(keys[i]), ver); + entries[i] = new KVDataObject(keys[i], ver, value); + } + } + } + + return entries; + } + + @RequestMapping(method = { RequestMethod.GET, + RequestMethod.POST }, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries") + @Override + public KVDataEntry[] getDataEntries(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccount.getDataEntriesTotalCount()); + return dataAccount.getDataEntries(pages[0], pages[1]); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts/address/{address}/entries/count") + @Override + public long getDataEntriesTotalCount(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { + + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + DataAccount dataAccount = dataAccountSet.getDataAccount(Bytes.fromBase58(address)); + + return dataAccount.getDataEntriesTotalCount(); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}") + @Override + public ContractInfo getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @PathVariable(name = "address") String address) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + return contractAccountSet.getContract(Bytes.fromBase58(address)); + } + + /** + * get more users by fromIndex and count; + * + * @param ledgerHash + * @param fromIndex + * @param count + * @return + */ + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/users") + @Override + public AccountHeader[] getUsers(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + UserAccountSet userAccountSet = ledger.getUserAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) userAccountSet.getTotalCount()); + return userAccountSet.getAccounts(pages[0], pages[1]); + } + + /** + * get more dataAccounts by fromIndex and count; + * + * @param ledgerHash + * @param fromIndex + * @param count + * @return + */ + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/accounts") + @Override + public AccountHeader[] getDataAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + DataAccountSet dataAccountSet = ledger.getDataAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) dataAccountSet.getTotalCount()); + return dataAccountSet.getAccounts(pages[0], pages[1]); + } + + @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts") + @Override + public AccountHeader[] getContractAccounts(@PathVariable(name = "ledgerHash") HashDigest ledgerHash, + @RequestParam(name = "fromIndex", required = false, defaultValue = "0") int fromIndex, + @RequestParam(name = "count", required = false, defaultValue = "-1") int count) { + LedgerRepository ledger = ledgerService.getLedger(ledgerHash); + LedgerBlock block = ledger.getLatestBlock(); + ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block); + int pages[] = QueryUtil.calFromIndexAndCount(fromIndex, count, (int) contractAccountSet.getTotalCount()); + return contractAccountSet.getAccounts(pages[0], pages[1]); + } + +} diff --git a/source/peer/src/main/resources/log4j2.xml b/source/peer/src/main/resources/log4j2.xml index c889aa69..b3630520 100644 --- a/source/peer/src/main/resources/log4j2.xml +++ b/source/peer/src/main/resources/log4j2.xml @@ -8,7 +8,7 @@ - + diff --git a/source/pom.xml b/source/pom.xml index 920d9301..eaaad8c5 100644 --- a/source/pom.xml +++ b/source/pom.xml @@ -8,11 +8,11 @@ spring-boot-starter-parent 2.0.6.RELEASE - - - - - + + + + + com.jd.blockchain jdchain-root @@ -92,8 +92,12 @@ mockito-core test + + org.springframework.boot + spring-boot-starter-log4j2 + test + - @@ -171,7 +175,7 @@ com.alibaba fastjson - 1.2.32 + 1.2.58 @@ -446,22 +450,22 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + diff --git a/source/sdk/sdk-base/pom.xml b/source/sdk/sdk-base/pom.xml index 6a30cb76..cd184f2f 100644 --- a/source/sdk/sdk-base/pom.xml +++ b/source/sdk/sdk-base/pom.xml @@ -1,58 +1,58 @@ - - 4.0.0 - - com.jd.blockchain - sdk - 1.1.0-SNAPSHOT - - sdk-base - - - - - com.jd.blockchain - ledger-model - ${project.version} - - - - com.jd.blockchain - consensus-framework - ${project.version} - - - binary-proto - com.jd.blockchain - - - crypto-framework - com.jd.blockchain - - - utils-common - com.jd.blockchain - - - - - - com.jd.blockchain - utils-serialize - ${project.version} - - - utils-common - com.jd.blockchain - - - - - - + + 4.0.0 + + com.jd.blockchain + sdk + 1.1.0-SNAPSHOT + + sdk-base + + + + + com.jd.blockchain + ledger-model + ${project.version} + + + + com.jd.blockchain + consensus-framework + ${project.version} + + + binary-proto + com.jd.blockchain + + + crypto-framework + com.jd.blockchain + + + utils-common + com.jd.blockchain + + + + + + com.jd.blockchain + utils-serialize + ${project.version} + + + utils-common + com.jd.blockchain + + + + + + \ No newline at end of file diff --git a/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java b/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java index a4a5c45a..6387bd48 100644 --- a/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java +++ b/source/sdk/sdk-base/src/test/java/test/com/jd/blockchain/sdk/proxy/BlockchainServiceProxyTest.java @@ -1,95 +1,91 @@ -package test.com.jd.blockchain.sdk.proxy; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.verify; - -public class BlockchainServiceProxyTest { - -// private static class ArgCaptorMatcher extends CustomMatcher { -// -// private T arg; -// -// public ArgCaptorMatcher() { -// super("OK"); -// } -// -// @Override -// public boolean matches(Object item) { -// this.arg = (T) item; -// return true; -// } -// -// public T getArg() { -// return arg; -// } -// } -// -// @Test -// public void testRegisterAccount() throws IOException { -// -// BlockchainKeyPair gatewayAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// BlockchainKeyPair sponsorAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// BlockchainKeyPair subjectAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// long sequenceNumber = 110; -// -// ArgCaptorMatcher txReqCaptor = new ArgCaptorMatcher<>(); -// -// TransactionService consensusService = Mockito.mocker(TransactionService.class); -// BlockchainQueryService queryService = Mockito.mocker(BlockchainQueryService.class); -// -// HashDigest txContentHash =CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8")); -// TxResponseMessage expectedResponse = new TxResponseMessage(txContentHash); -// expectedResponse.setExecutionState(ExecutionState.SUCCESS); -// -// when(consensusService.process(argThat(txReqCaptor))).thenReturn(expectedResponse); -// -// HashDigest ledgerHash = CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8")); -// -// BlockchainTransactionService serviceProxy = new BlockchainServiceProxy(consensusService, queryService); -// -// TransactionTemplate txTemplate = serviceProxy.newTransaction(ledgerHash); -// txTemplate.setSubject(subjectAccount.getAddress(), sequenceNumber); -// -// BlockchainKeyPair regAccountKeyPair = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); -// AccountStateType stateType = AccountStateType.MAP; -// txTemplate.users().register(regAccountKeyPair.getIdentity(), stateType); -// -// PreparedTransaction prepTx = txTemplate.prepare(); -// HashDigest txHash = prepTx.getHash(); -// prepTx.sign(sponsorAccount); -// -// TransactionResponse result = prepTx.commit(); -// -// // 验证; -// // 仅被提交一次; -// verify(consensusService, times(1)).process(any()); -// -// assertEquals(ExecutionState.SUCCESS, result.getExecutionState()); -// -// // 验证内容; -// TransactionRequest resolvedTxRequest = txReqCaptor.getArg(); -// -// TransactionContent resolvedTxContent = resolvedTxRequest.getTransactionContent(); -// -// assertEquals(txHash, resolvedTxContent.getHash()); -// -// assertEquals(subjectAccount.getAddress(), resolvedTxContent.getSubjectAccount()); -// assertEquals(sequenceNumber, resolvedTxContent.getSequenceNumber()); -// -// -// Operation[] resolvedOps = resolvedTxContent.getOperations(); -// assertEquals(1, resolvedOps.length); -// Operation resolvedOP = resolvedOps[0]; -//// assertEquals(OperationType.REGISTER_USER.CODE, resolvedOP.getCode()); -// -// UserRegisterOpTemplate accRegOP = new UserRegisterOpTemplate(); -// accRegOP.resolvFrom((OpBlob) resolvedOP); -// -// assertEquals(regAccountKeyPair.getAddress(), accRegOP.getId().getAddress()); -// assertEquals(regAccountKeyPair.getPubKey().getType(), accRegOP.getId().getPubKey().getType()); -// assertEquals(regAccountKeyPair.getPubKey().getValue(), accRegOP.getId().getPubKey().getValue()); -// assertEquals(stateType, accRegOP.getStateType()); -// } - -} +package test.com.jd.blockchain.sdk.proxy; + +public class BlockchainServiceProxyTest { + +// private static class ArgCaptorMatcher extends CustomMatcher { +// +// private T arg; +// +// public ArgCaptorMatcher() { +// super("OK"); +// } +// +// @Override +// public boolean matches(Object item) { +// this.arg = (T) item; +// return true; +// } +// +// public T getArg() { +// return arg; +// } +// } +// +// @Test +// public void testRegisterAccount() throws IOException { +// +// BlockchainKeyPair gatewayAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); +// BlockchainKeyPair sponsorAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); +// BlockchainKeyPair subjectAccount = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); +// long sequenceNumber = 110; +// +// ArgCaptorMatcher txReqCaptor = new ArgCaptorMatcher<>(); +// +// TransactionService consensusService = Mockito.mocker(TransactionService.class); +// BlockchainQueryService queryService = Mockito.mocker(BlockchainQueryService.class); +// +// HashDigest txContentHash =CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8")); +// TxResponseMessage expectedResponse = new TxResponseMessage(txContentHash); +// expectedResponse.setExecutionState(ExecutionState.SUCCESS); +// +// when(consensusService.process(argThat(txReqCaptor))).thenReturn(expectedResponse); +// +// HashDigest ledgerHash = CryptoUtils.hash(CryptoAlgorithm.SHA_256).hash(UUID.randomUUID().toString().getBytes("UTF-8")); +// +// BlockchainTransactionService serviceProxy = new BlockchainServiceProxy(consensusService, queryService); +// +// TransactionTemplate txTemplate = serviceProxy.newTransaction(ledgerHash); +// txTemplate.setSubject(subjectAccount.getAddress(), sequenceNumber); +// +// BlockchainKeyPair regAccountKeyPair = BlockchainKeyGenerator.getInstance().generate(CryptoKeyType.ED25519); +// AccountStateType stateType = AccountStateType.MAP; +// txTemplate.users().register(regAccountKeyPair.getIdentity(), stateType); +// +// PreparedTransaction prepTx = txTemplate.prepare(); +// HashDigest txHash = prepTx.getHash(); +// prepTx.sign(sponsorAccount); +// +// TransactionResponse result = prepTx.commit(); +// +// // 验证; +// // 仅被提交一次; +// verify(consensusService, times(1)).process(any()); +// +// assertEquals(ExecutionState.SUCCESS, result.getExecutionState()); +// +// // 验证内容; +// TransactionRequest resolvedTxRequest = txReqCaptor.getArg(); +// +// TransactionContent resolvedTxContent = resolvedTxRequest.getTransactionContent(); +// +// assertEquals(txHash, resolvedTxContent.getHash()); +// +// assertEquals(subjectAccount.getAddress(), resolvedTxContent.getSubjectAccount()); +// assertEquals(sequenceNumber, resolvedTxContent.getSequenceNumber()); +// +// +// Operation[] resolvedOps = resolvedTxContent.getOperations(); +// assertEquals(1, resolvedOps.length); +// Operation resolvedOP = resolvedOps[0]; +//// assertEquals(OperationType.REGISTER_USER.CODE, resolvedOP.getCode()); +// +// UserRegisterOpTemplate accRegOP = new UserRegisterOpTemplate(); +// accRegOP.resolvFrom((OpBlob) resolvedOP); +// +// assertEquals(regAccountKeyPair.getAddress(), accRegOP.getId().getAddress()); +// assertEquals(regAccountKeyPair.getPubKey().getType(), accRegOP.getId().getPubKey().getType()); +// assertEquals(regAccountKeyPair.getPubKey().getValue(), accRegOP.getId().getPubKey().getValue()); +// assertEquals(stateType, accRegOP.getStateType()); +// } + +} diff --git a/source/sdk/sdk-mq/pom.xml b/source/sdk/sdk-mq/pom.xml deleted file mode 100644 index 5a735573..00000000 --- a/source/sdk/sdk-mq/pom.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - sdk - com.jd.blockchain - 0.9.0-SNAPSHOT - - 4.0.0 - - sdk-mq - - - UTF-8 - 1.8 - 1.8 - - - - - junit - junit - 4.11 - test - - - com.jd.blockchain - sdk-base - ${project.version} - - - com.lmax - disruptor - - - io.nats - jnats - - - - - - - diff --git a/source/state-transfer/pom.xml b/source/state-transfer/pom.xml deleted file mode 100644 index d17c8e03..00000000 --- a/source/state-transfer/pom.xml +++ /dev/null @@ -1,34 +0,0 @@ - - 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 deleted file mode 100644 index 237a6d47..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequence.java +++ /dev/null @@ -1,75 +0,0 @@ -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 deleted file mode 100644 index aaf6e7f5..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceElement.java +++ /dev/null @@ -1,53 +0,0 @@ -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 deleted file mode 100644 index 6f0f2e10..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/DataSequenceInfo.java +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index e137b929..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReader.java +++ /dev/null @@ -1,39 +0,0 @@ -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 deleted file mode 100644 index 3d581b2d..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceReaderImpl.java +++ /dev/null @@ -1,59 +0,0 @@ -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 deleted file mode 100644 index b45eb3ac..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriter.java +++ /dev/null @@ -1,30 +0,0 @@ -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 deleted file mode 100644 index c510e843..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/callback/DataSequenceWriterImpl.java +++ /dev/null @@ -1,142 +0,0 @@ -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 需要更新到本地结点的数据序列元素List - * @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 deleted file mode 100644 index 9e0afbe5..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/comparator/DataSequenceComparator.java +++ /dev/null @@ -1,32 +0,0 @@ -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 deleted file mode 100644 index 5e6248c0..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/exception/DataSequenceException.java +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 6c67e8c8..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSDefaultMessageExecutor.java +++ /dev/null @@ -1,80 +0,0 @@ -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; - -/** - * 数据序列差异提供者使用,解析收到的差异请求消息并产生响应 - * @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 请求消息的Key - * @param data 需要解码的字节数组 - * @param session 指定响应需要使用的目标结点会话 - * @return 配置为自动响应时,返回值为响应的字节数组,配置为手动响应时,不需要关注返回值 - */ - - @Override - public byte[] receive(String key, byte[] data, RemoteSession session) { - - try { - Object object = DSMsgResolverFactory.getDecoder(dsWriter, dsReader).decode(data); - - // 解析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)); - } - // 解析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 deleted file mode 100644 index c0dfae8d..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DSMsgResolverFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.jd.blockchain.statetransfer.message; - -import com.jd.blockchain.statetransfer.callback.DataSequenceReader; -import com.jd.blockchain.statetransfer.callback.DataSequenceWriter; - -/** - * 数据序列消息解析器工厂 - * @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); - } - - /** - * 获得数据序列消息解码器实例 - * @param dsWriter 差异请求者执行数据序列更新的执行器 - * @param dsReader 差异响应者执行数据序列读取的执行器 - * @return 消息解码器实例 - */ - 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 deleted file mode 100644 index a4131e61..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceLoadMessage.java +++ /dev/null @@ -1,28 +0,0 @@ -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 deleted file mode 100644 index 6bfa4c97..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgDecoder.java +++ /dev/null @@ -1,107 +0,0 @@ -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; - -/** - * 数据序列消息解码器 - * @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 解码后的对象 - */ - 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 deleted file mode 100644 index 71b3ef4c..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/message/DataSequenceMsgEncoder.java +++ /dev/null @@ -1,133 +0,0 @@ -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与toHeight相同的情况,即每次只对一个高度的差异内容进行编码并响应 - * 把消息编码成字节数组,再交给通信层传输 - * @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,获得这个高度上的所有差异的数据序列内容,并组织成DataSequenceElement结构 - 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 deleted file mode 100644 index 97b14602..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSProcessManager.java +++ /dev/null @@ -1,186 +0,0 @@ -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 deleted file mode 100644 index 45fc89fb..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/process/DSTransferProcess.java +++ /dev/null @@ -1,216 +0,0 @@ -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 对差异字节数组的解码结果 - */ - 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 deleted file mode 100644 index af62bd6c..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSDiffRequestResult.java +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 7f6d48cc..00000000 --- a/source/state-transfer/src/main/java/com/jd/blockchain/statetransfer/result/DSInfoResponseResult.java +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index 5741262e..00000000 --- a/source/state-transfer/src/test/java/test/com/jd/blockchain/statetransfer/StateTransferLayerTest.java +++ /dev/null @@ -1,155 +0,0 @@ -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() { - - // 产生两个唯一的数据序列Id标识 - 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/storage/storage-redis/pom.xml b/source/storage/storage-redis/pom.xml index 77cd8758..2b3b78dd 100644 --- a/source/storage/storage-redis/pom.xml +++ b/source/storage/storage-redis/pom.xml @@ -1,42 +1,42 @@ - - 4.0.0 - - com.jd.blockchain - storage - 1.1.0-SNAPSHOT - - storage-redis - - - - com.jd.blockchain - storage-service - ${project.version} - - - com.jd.blockchain - utils-common - ${project.version} - - - org.springframework.boot - spring-boot - - - org.springframework.boot - spring-boot-autoconfigure - - - org.springframework.boot - spring-boot-configuration-processor - true - - - - redis.clients - jedis - - - + + 4.0.0 + + com.jd.blockchain + storage + 1.1.0-SNAPSHOT + + storage-redis + + + + com.jd.blockchain + storage-service + ${project.version} + + + com.jd.blockchain + utils-common + ${project.version} + + + org.springframework.boot + spring-boot + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + redis.clients + jedis + + + \ No newline at end of file diff --git a/source/storage/storage-rocksdb/pom.xml b/source/storage/storage-rocksdb/pom.xml index 7c60abd5..e644c873 100644 --- a/source/storage/storage-rocksdb/pom.xml +++ b/source/storage/storage-rocksdb/pom.xml @@ -31,6 +31,10 @@ org.apache.commons commons-collections4 + + junit + junit +