diff --git a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java
index fdd040fb..ac3c94f4 100644
--- a/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java
+++ b/source/crypto/crypto-classic/src/main/java/com/jd/blockchain/crypto/service/classic/ClassicAlgorithm.java
@@ -7,15 +7,21 @@ public final class ClassicAlgorithm {
public static final CryptoAlgorithm ED25519 = CryptoAlgorithmDefinition.defineSignature("ED25519", false,
(byte) 21);
- public static final CryptoAlgorithm ECDSA = CryptoAlgorithmDefinition.defineSignature("ECDSA", false, (byte) 22);
- public static final CryptoAlgorithm RSA = CryptoAlgorithmDefinition.defineSignature("RSA", true, (byte) 23);
+ public static final CryptoAlgorithm ECDSA = CryptoAlgorithmDefinition.defineSignature("ECDSA", false,
+ (byte) 22);
- public static final CryptoAlgorithm SHA256 = CryptoAlgorithmDefinition.defineHash("SHA256", (byte) 24);
+ public static final CryptoAlgorithm RSA = CryptoAlgorithmDefinition.defineSignature("RSA", true,
+ (byte) 23);
- public static final CryptoAlgorithm RIPEMD160 = CryptoAlgorithmDefinition.defineHash("RIPEMD160", (byte) 25);
+ public static final CryptoAlgorithm SHA256 = CryptoAlgorithmDefinition.defineHash("SHA256",
+ (byte) 24);
- public static final CryptoAlgorithm AES = CryptoAlgorithmDefinition.defineSymmetricEncryption("AES", (byte) 26);
+ public static final CryptoAlgorithm RIPEMD160 = CryptoAlgorithmDefinition.defineHash("RIPEMD160",
+ (byte) 25);
+
+ public static final CryptoAlgorithm AES = CryptoAlgorithmDefinition.defineSymmetricEncryption("AES",
+ (byte) 26);
public static final CryptoAlgorithm JVM_SECURE_RANDOM = CryptoAlgorithmDefinition.defineRandom("JVM-SECURE-RANDOM",
(byte) 27);
diff --git a/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java
new file mode 100644
index 00000000..a0eebbc4
--- /dev/null
+++ b/source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java
@@ -0,0 +1,18 @@
+package test.com.jd.blockchain.crypto.service.classic;
+
+import com.jd.blockchain.utils.Bytes;
+import com.jd.blockchain.utils.codec.HexUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EncodeTest {
+
+ @Test
+ public void test() {
+ String pubKey = "7VeRLdGtSz1Y91gjLTqEdnkotzUfaAqdap3xw6fQ1yKHkvVq";
+ Bytes bytes = Bytes.fromBase58(pubKey);
+ String hexString = HexUtils.encode(bytes.toBytes());
+ String code = hexString.substring(2, 4);
+ Assert.assertEquals(code, "15"); // 15为十六进制,对应十进制为21(ED25519)
+ }
+}
diff --git a/source/gateway/pom.xml b/source/gateway/pom.xml
index 3150363e..9cb95d06 100644
--- a/source/gateway/pom.xml
+++ b/source/gateway/pom.xml
@@ -45,7 +45,7 @@
com.jd.blockchain
- browser
+ explorer
@@ -78,6 +78,23 @@
${commons-io.version}
+
+ org.bitbucket.mstrobel
+ procyon-core
+
+
+ org.bitbucket.mstrobel
+ procyon-expressions
+
+
+ org.bitbucket.mstrobel
+ procyon-reflection
+
+
+ org.bitbucket.mstrobel
+ procyon-compilertools
+
+
org.springframework.boot
spring-boot-starter-web
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java
new file mode 100644
index 00000000..8caf66f0
--- /dev/null
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java
@@ -0,0 +1,249 @@
+package com.jd.blockchain.gateway.decompiler.loads;
+
+import com.strobel.assembler.ir.ConstantPool;
+import com.strobel.assembler.metadata.Buffer;
+import com.strobel.assembler.metadata.ClasspathTypeLoader;
+import com.strobel.assembler.metadata.ITypeLoader;
+import com.strobel.core.StringUtilities;
+import com.strobel.core.VerifyArgument;
+
+import java.io.ByteArrayInputStream;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class BytesTypeLoader implements ITypeLoader {
+
+ private final static Logger LOG = Logger.getLogger(BytesTypeLoader.class.getSimpleName());
+
+ private final ITypeLoader defaultTypeLoader;
+ private final Map> packageLocations;
+ private final Map knownBytes;
+
+ private String name;
+
+ public BytesTypeLoader(byte[] bytes) {
+ this(new ClasspathTypeLoader(), bytes);
+ }
+
+ public BytesTypeLoader(final ITypeLoader defaultTypeLoader, byte[] bytes) {
+ this.defaultTypeLoader = VerifyArgument.notNull(defaultTypeLoader, "defaultTypeLoader");
+ this.packageLocations = new LinkedHashMap<>();
+ this.knownBytes = new LinkedHashMap<>();
+ Buffer innerNameBuffer = new Buffer();
+ if (tryLoadTypeFromBytes(bytes, innerNameBuffer)) {
+ this.name = getInternalNameFromClassFile(innerNameBuffer);
+ this.knownBytes.put(this.name, bytes);
+ } else {
+ throw new IllegalStateException("Input Class Bytes Exception !!!");
+ }
+ }
+
+ @Override
+ public boolean tryLoadType(final String typeNameOrPath, final Buffer buffer) {
+ VerifyArgument.notNull(typeNameOrPath, "typeNameOrPath");
+ VerifyArgument.notNull(buffer, "buffer");
+
+ if (LOG.isLoggable(Level.FINE)) {
+ LOG.fine("Attempting to load type: " + typeNameOrPath + "...");
+ }
+
+ final boolean hasExtension = StringUtilities.endsWithIgnoreCase(typeNameOrPath, ".class");
+
+ if (hasExtension) {
+ return false;
+ }
+
+ String internalName = typeNameOrPath;
+
+ if (tryLoadTypeFromName(internalName, buffer)) {
+ return true;
+ }
+
+ for (int lastDelimiter = internalName.lastIndexOf('/');
+ lastDelimiter != -1;
+ lastDelimiter = internalName.lastIndexOf('/')) {
+
+ internalName = internalName.substring(0, lastDelimiter) + "$" +
+ internalName.substring(lastDelimiter + 1);
+
+ if (tryLoadTypeFromName(internalName, buffer)) {
+ return true;
+ }
+ }
+
+ if (LOG.isLoggable(Level.FINER)) {
+ LOG.finer("Failed to load type: " + typeNameOrPath + ".");
+ }
+
+ return false;
+ }
+
+ private boolean tryLoadTypeFromName(final String internalName, final Buffer buffer) {
+ if (tryLoadFromKnownLocation(internalName, buffer)) {
+ return true;
+ }
+
+ if (defaultTypeLoader.tryLoadType(internalName, buffer)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean tryLoadFromKnownLocation(final String internalName, final Buffer buffer) {
+ final byte[] knownFile = knownBytes.get(internalName);
+
+ if (tryLoadBytes(knownFile, buffer)) {
+ return true;
+ }
+
+ final int packageEnd = internalName.lastIndexOf('/');
+
+ String head;
+ String tail;
+
+ if (packageEnd < 0 || packageEnd >= internalName.length()) {
+ head = StringUtilities.EMPTY;
+ tail = internalName;
+ }
+ else {
+ head = internalName.substring(0, packageEnd);
+ tail = internalName.substring(packageEnd + 1);
+ }
+
+ while (true) {
+ final LinkedHashSet directories = packageLocations.get(head);
+
+ if (directories != null) {
+ for (final byte[] directory : directories) {
+ if (tryLoadBytes(internalName, directory, buffer, true)) {
+ return true;
+ }
+ }
+ }
+
+ final int split = head.lastIndexOf('/');
+
+ if (split <= 0) {
+ break;
+ }
+
+ tail = head.substring(split + 1) + '/' + tail;
+ head = head.substring(0, split);
+ }
+
+ return false;
+ }
+
+ private boolean tryLoadBytes(final byte[] bytes, final Buffer buffer) {
+
+ if (bytes == null || bytes.length == 0) {
+ return false;
+ }
+
+ int length = bytes.length;
+ buffer.position(0);
+ buffer.reset(length);
+ new ByteArrayInputStream(bytes).read(buffer.array(), 0, length);
+ buffer.position(0);
+
+ return true;
+ }
+
+ private boolean tryLoadBytes(final String internalName, final byte[] bytes, final Buffer buffer, final boolean trustName) {
+ if (!tryLoadBytes(bytes, buffer)) {
+ return false;
+ }
+
+ final String actualName = getInternalNameFromClassFile(buffer);
+
+ final String name = trustName ? (internalName != null ? internalName : actualName)
+ : actualName;
+
+ if (name == null) {
+ return false;
+ }
+
+ final boolean nameMatches = StringUtilities.equals(actualName, internalName);
+
+ final boolean result = internalName == null || nameMatches;
+
+ if (result) {
+ final int packageEnd = name.lastIndexOf('/');
+ final String packageName;
+
+ if (packageEnd < 0 || packageEnd >= name.length()) {
+ packageName = StringUtilities.EMPTY;
+ }
+ else {
+ packageName = name.substring(0, packageEnd);
+ }
+
+ registerKnownPath(packageName, bytes);
+
+ knownBytes.put(actualName, bytes);
+
+ }
+ else {
+ buffer.reset(0);
+ }
+
+ return result;
+ }
+
+ private void registerKnownPath(final String packageName, final byte[] directory) {
+ if (directory == null || directory.length == 0) {
+ return;
+ }
+
+ LinkedHashSet directories = packageLocations.get(packageName);
+
+ if (directories == null) {
+ packageLocations.put(packageName, directories = new LinkedHashSet<>());
+ }
+
+ if (!directories.add(directory)) {
+ return;
+ }
+ }
+
+ private static String getInternalNameFromClassFile(final Buffer b) {
+ final long magic = b.readInt() & 0xFFFFFFFFL;
+
+ if (magic != 0xCAFEBABEL) {
+ return null;
+ }
+
+ b.readUnsignedShort(); // minor version
+ b.readUnsignedShort(); // major version
+
+ final ConstantPool constantPool = ConstantPool.read(b);
+
+ b.readUnsignedShort(); // access flags
+
+ final ConstantPool.TypeInfoEntry thisClass = constantPool.getEntry(b.readUnsignedShort());
+
+ b.position(0);
+
+ return thisClass.getName();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ private boolean tryLoadTypeFromBytes(byte[] bytes, Buffer buffer) {
+ if (bytes == null || bytes.length == 0 || buffer == null) {
+ return false;
+ }
+ int length = bytes.length;
+ buffer.position(0);
+ buffer.reset(length);
+ new ByteArrayInputStream(bytes).read(buffer.array(), 0, length);
+ buffer.position(0);
+ return true;
+ }
+}
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java
new file mode 100644
index 00000000..0a66da9f
--- /dev/null
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java
@@ -0,0 +1,218 @@
+package com.jd.blockchain.gateway.decompiler.utils;
+
+import com.jd.blockchain.gateway.decompiler.loads.BytesTypeLoader;
+import com.strobel.assembler.metadata.JarTypeLoader;
+import com.strobel.decompiler.Decompiler;
+import com.strobel.decompiler.DecompilerSettings;
+import com.strobel.decompiler.PlainTextOutput;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.jar.JarFile;
+
+public class DecompilerUtils {
+
+ public static final AtomicLong SAVE_INDEX = new AtomicLong();
+
+ public static final String MANIFEST_MF = "/META-INF/MANIFEST.MF";
+
+ public static final String MAIN_CLASS = "Main-Class";
+
+ public static String SAVE_DIR = null;
+
+ static {
+ init();
+ }
+
+ private static void init() {
+ try {
+ URL url = DecompilerUtils.class
+ .getProtectionDomain()
+ .getCodeSource()
+ .getLocation();
+ String currPath = java.net.URLDecoder.decode(url.getPath(), "UTF-8");
+ if (currPath.contains("!/")) {
+ currPath = currPath.substring(5, currPath.indexOf("!/"));
+ }
+ if (currPath.endsWith(".jar")) {
+ currPath = currPath.substring(0, currPath.lastIndexOf("/") + 1);
+ }
+ File file = new File(currPath);
+ String homeDir = file.getParent();
+ SAVE_DIR = homeDir + File.separator + "temp";
+ File dir = new File(SAVE_DIR);
+ if (!dir.exists()) {
+ dir.mkdir();
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+
+ }
+
+ public static String decompile(String classPath) {
+
+ String decompileJava;
+
+ try (StringWriter stringWriter = new StringWriter()) {
+
+ final DecompilerSettings settings = DecompilerSettings.javaDefaults();
+
+ Decompiler.decompile(
+ classPath,
+ new PlainTextOutput(stringWriter),
+ settings
+ );
+ decompileJava = stringWriter.toString();
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ return decompileJava;
+ }
+
+ public static List readManifest2Array(final String jarFilePath, final String charSet) {
+ String manifest = readManifest(jarFilePath, charSet);
+ String[] manifests = manifest.split("\r\n");
+ return Arrays.asList(manifests);
+ }
+
+ public static String readManifest(final String jarFilePath, final String charSet) {
+ return decompileJarFile(jarFilePath, MANIFEST_MF, false, charSet);
+ }
+
+ public static String decompileMainClassFromBytes(byte[] bytes) {
+ try {
+ String jarFile = writeBytes(bytes, SAVE_DIR, "jar");
+ String decompileJava = decompileMainClassFromJarFile(jarFile);
+ // 然后删除jarFile文件
+ FileUtils.forceDelete(new File(jarFile));
+ return decompileJava;
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static String decompileMainClassFromJarFile(final String jarFilePath) {
+ // 首先获取Main-Class
+ List manifests = readManifest2Array(jarFilePath, null);
+ if (manifests == null || manifests.size() == 0) {
+ throw new IllegalStateException("MANIFEST.MF not Exist or is Empty !!!");
+ } else {
+ String mainClass = null;
+ for (String s : manifests) {
+ String inner = s.trim().replaceAll(" ", "");
+ if (inner.startsWith(MAIN_CLASS)) {
+ mainClass = inner.split(":")[1];
+ break;
+ }
+ }
+ if (mainClass == null || mainClass.length() == 0) {
+ throw new IllegalStateException("MANIFEST.MF has not Main-Class !!!");
+ }
+
+ // 然后读取MainClass中的内容并进行反编译
+ String classPath = mainClass.replaceAll("\\.", "/");
+ return decompileJarFile(jarFilePath, classPath, true, null);
+ }
+ }
+
+ public static String decompileJarFile(final String jarFilePath, final String source, final boolean isClass, final String charSet) {
+
+ // 对于Class文件和非Class文件处理方式不同
+ if (!isClass) {
+ // 非Class文件不需要编译,直接从文件中读取即可
+ String innerSource = source;
+ if (!innerSource.startsWith("/")) {
+ innerSource = "/" + innerSource;
+ }
+ try {
+ URL jarUrl = new URL("jar:file:" + jarFilePath + "!" + innerSource);
+ InputStream inputStream = jarUrl.openStream();
+ byte[] bytes = IOUtils.toByteArray(inputStream);
+ if (charSet == null) {
+ return new String(bytes);
+ }
+ return new String(bytes, charSet);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
+ } else {
+
+ String decompileJava;
+
+ try (StringWriter stringWriter = new StringWriter()) {
+
+ JarFile jarFile = new JarFile(jarFilePath);
+
+ JarTypeLoader jarTypeLoader = new JarTypeLoader(jarFile);
+
+ final DecompilerSettings settings = DecompilerSettings.javaDefaults();
+
+ settings.setTypeLoader(jarTypeLoader);
+
+ Decompiler.decompile(
+ source,
+ new PlainTextOutput(stringWriter),
+ settings
+ );
+ decompileJava = stringWriter.toString();
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ return decompileJava;
+ }
+ }
+
+ public static String decompile(byte[] classBytes) {
+
+ String decompileJava;
+
+ try (StringWriter stringWriter = new StringWriter()) {
+
+ BytesTypeLoader bytesTypeLoader = new BytesTypeLoader(classBytes);
+
+ String name = bytesTypeLoader.getName();
+
+ final DecompilerSettings settings = DecompilerSettings.javaDefaults();
+
+ settings.setTypeLoader(bytesTypeLoader);
+
+ Decompiler.decompile(
+ name,
+ new PlainTextOutput(stringWriter),
+ settings
+ );
+ decompileJava = stringWriter.toString();
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ return decompileJava;
+ }
+
+ public static String decompile(InputStream in) {
+ try {
+ return decompile(IOUtils.toByteArray(in));
+ } catch (final Exception e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public static byte[] read2Bytes(String filePath) throws IOException {
+ return FileUtils.readFileToByteArray(new File(filePath));
+ }
+
+ public static String writeBytes(byte[] bytes, String directory, String suffix) throws IOException {
+ String saveFileName = System.currentTimeMillis() + "-" + SAVE_INDEX.incrementAndGet() + "." + suffix;
+ File saveFile = new File(directory + File.separator + saveFileName);
+ FileUtils.writeByteArrayToFile(saveFile, bytes);
+ return saveFile.getPath();
+ }
+}
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java
index 6cd1828c..340527c7 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryService.java
@@ -2,7 +2,9 @@ package com.jd.blockchain.gateway.service;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.ledger.ParticipantNode;
+import com.jd.blockchain.sdk.ContractSettings;
import com.jd.blockchain.sdk.LedgerInitSettings;
+import com.jd.blockchain.utils.Bytes;
/**
* queryService only for gateway;
@@ -34,4 +36,15 @@ public interface GatewayQueryService {
* @return
*/
LedgerInitSettings getLedgerInitSettings(HashDigest ledgerHash);
+
+ /**
+ * 获取账本指定合约信息
+ *
+ * @param ledgerHash
+ * 账本Hash
+ * @param address
+ * 合约地址
+ * @return
+ */
+ ContractSettings getContractSettings(HashDigest ledgerHash, String address);
}
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
index 1a6c0267..4421dde1 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayQueryServiceHandler.java
@@ -7,8 +7,11 @@ import com.jd.blockchain.consensus.bftsmart.BftsmartConsensusProvider;
import com.jd.blockchain.consensus.mq.MsgQueueConsensusProvider;
import com.jd.blockchain.crypto.HashDigest;
import com.jd.blockchain.gateway.PeerService;
+import com.jd.blockchain.gateway.decompiler.utils.DecompilerUtils;
+import com.jd.blockchain.ledger.ContractInfo;
import com.jd.blockchain.ledger.LedgerMetadata;
import com.jd.blockchain.ledger.ParticipantNode;
+import com.jd.blockchain.sdk.ContractSettings;
import com.jd.blockchain.sdk.LedgerInitSettings;
import com.jd.blockchain.utils.QueryUtil;
import com.jd.blockchain.utils.codec.HexUtils;
@@ -53,6 +56,21 @@ public class GatewayQueryServiceHandler implements GatewayQueryService {
return initLedgerInitSettings(participantNodes, ledgerMetadata);
}
+ @Override
+ public ContractSettings getContractSettings(HashDigest ledgerHash, String address) {
+ ContractInfo contractInfo = peerService.getQueryService().getContract(ledgerHash, address);
+ return contractSettings(contractInfo);
+ }
+
+ private ContractSettings contractSettings(ContractInfo contractInfo) {
+ ContractSettings contractSettings = new ContractSettings(contractInfo.getAddress(), contractInfo.getPubKey(), contractInfo.getRootHash());
+ byte[] chainCodeBytes = contractInfo.getChainCode();
+ // 将反编译chainCode
+ String mainClassJava = DecompilerUtils.decompileMainClassFromBytes(chainCodeBytes);
+ contractSettings.setChainCode(mainClassJava);
+ return contractSettings;
+ }
+
/**
* 初始化账本配置
*
diff --git a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
index 9b41bcc0..91c498aa 100644
--- a/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
+++ b/source/gateway/src/main/java/com/jd/blockchain/gateway/web/BlockBrowserController.java
@@ -8,6 +8,7 @@ import com.jd.blockchain.gateway.service.DataRetrievalService;
import com.jd.blockchain.gateway.service.GatewayQueryService;
import com.jd.blockchain.ledger.*;
import com.jd.blockchain.sdk.BlockchainExtendQueryService;
+import com.jd.blockchain.sdk.ContractSettings;
import com.jd.blockchain.sdk.LedgerInitSettings;
import com.jd.blockchain.tools.keygen.KeyGenCommand;
import com.jd.blockchain.utils.BaseConstant;
@@ -23,6 +24,7 @@ import java.util.List;
@RestController
@RequestMapping(path = "/")
public class BlockBrowserController implements BlockchainExtendQueryService {
+
private static org.slf4j.Logger LOGGER = LoggerFactory.getLogger(BlockBrowserController.class);
@Autowired
@@ -263,10 +265,15 @@ public class BlockBrowserController implements BlockchainExtendQueryService {
}
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}")
+ public ContractSettings getContractSettings(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
+ @PathVariable(name = "address") String address) {
+ return gatewayQueryService.getContractSettings(ledgerHash, address);
+ }
+
+// @RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}")
@Override
- public AccountHeader getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
- @PathVariable(name = "address") String address) {
- return peerService.getQueryService().getContract(ledgerHash, address);
+ public ContractInfo getContract(HashDigest ledgerHash, String address) {
+ return peerService.getQueryService().getContract(ledgerHash, address);
}
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/blocks/latest")
@@ -450,7 +457,8 @@ public class BlockBrowserController implements BlockchainExtendQueryService {
}
@RequestMapping(method = RequestMethod.GET, value = "ledgers/{ledgerHash}/**/search")
- public Object dataRetrieval(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,HttpServletRequest request) {
+ public Object dataRetrieval(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
+ HttpServletRequest request) {
String result;
if (dataRetrievalUrl == null || dataRetrievalUrl.length() <= 0) {
result = "{'message':'OK','data':'" + "data.retrieval.url is empty" + "'}";
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
index 977f2c2e..c4a94ee6 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/ContractAccount.java
@@ -5,9 +5,10 @@ import com.jd.blockchain.crypto.PubKey;
import com.jd.blockchain.ledger.AccountHeader;
import com.jd.blockchain.ledger.BytesValue;
import com.jd.blockchain.ledger.BytesData;
+import com.jd.blockchain.ledger.ContractInfo;
import com.jd.blockchain.utils.Bytes;
-public class ContractAccount implements AccountHeader {
+public class ContractAccount implements ContractInfo {
private static final Bytes CONTRACT_INFO_PREFIX = Bytes.fromString("INFO" + LedgerConsts.KEY_SEPERATOR);
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 2806b5af..13625600 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
@@ -5,19 +5,7 @@ import java.util.List;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.crypto.HashDigest;
-import com.jd.blockchain.ledger.AccountHeader;
-import com.jd.blockchain.ledger.BytesValue;
-import com.jd.blockchain.ledger.KVDataEntry;
-import com.jd.blockchain.ledger.KVDataObject;
-import com.jd.blockchain.ledger.KVDataVO;
-import com.jd.blockchain.ledger.KVInfoVO;
-import com.jd.blockchain.ledger.LedgerBlock;
-import com.jd.blockchain.ledger.LedgerInfo;
-import com.jd.blockchain.ledger.LedgerMetadata;
-import com.jd.blockchain.ledger.LedgerTransaction;
-import com.jd.blockchain.ledger.ParticipantNode;
-import com.jd.blockchain.ledger.TransactionState;
-import com.jd.blockchain.ledger.UserInfo;
+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;
@@ -367,7 +355,7 @@ public class LedgerQueryService implements BlockchainQueryService {
}
@Override
- public AccountHeader getContract(HashDigest ledgerHash, String address) {
+ public ContractInfo getContract(HashDigest ledgerHash, String address) {
LedgerRepository ledger = ledgerService.getLedger(ledgerHash);
LedgerBlock block = ledger.getLatestBlock();
ContractAccountSet contractAccountSet = ledger.getContractAccountSet(block);
diff --git a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
index 4a0e1ed5..5a673722 100644
--- a/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
+++ b/source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractLedgerContext.java
@@ -5,23 +5,7 @@ import java.util.List;
import com.jd.blockchain.contract.LedgerContext;
import com.jd.blockchain.crypto.HashDigest;
-import com.jd.blockchain.ledger.AccountHeader;
-import com.jd.blockchain.ledger.BlockchainIdentity;
-import com.jd.blockchain.ledger.BytesValue;
-import com.jd.blockchain.ledger.BytesData;
-import com.jd.blockchain.ledger.DataAccountKVSetOperation;
-import com.jd.blockchain.ledger.DataAccountRegisterOperation;
-import com.jd.blockchain.ledger.KVDataEntry;
-import com.jd.blockchain.ledger.KVInfoVO;
-import com.jd.blockchain.ledger.LedgerBlock;
-import com.jd.blockchain.ledger.LedgerInfo;
-import com.jd.blockchain.ledger.LedgerMetadata;
-import com.jd.blockchain.ledger.LedgerTransaction;
-import com.jd.blockchain.ledger.Operation;
-import com.jd.blockchain.ledger.ParticipantNode;
-import com.jd.blockchain.ledger.TransactionState;
-import com.jd.blockchain.ledger.UserInfo;
-import com.jd.blockchain.ledger.UserRegisterOperation;
+import com.jd.blockchain.ledger.*;
import com.jd.blockchain.ledger.core.impl.OperationHandleContext;
import com.jd.blockchain.transaction.BlockchainQueryService;
import com.jd.blockchain.transaction.DataAccountKVSetOperationBuilder;
@@ -186,7 +170,7 @@ public class ContractLedgerContext implements LedgerContext {
}
@Override
- public AccountHeader getContract(HashDigest ledgerHash, String address) {
+ public ContractInfo getContract(HashDigest ledgerHash, String address) {
return innerQueryService.getContract(ledgerHash, address);
}
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java
new file mode 100644
index 00000000..cb1da5c4
--- /dev/null
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java
@@ -0,0 +1,13 @@
+package com.jd.blockchain.ledger;
+
+import com.jd.blockchain.binaryproto.DataContract;
+import com.jd.blockchain.binaryproto.DataField;
+import com.jd.blockchain.binaryproto.PrimitiveType;
+import com.jd.blockchain.consts.DataCodes;
+
+@DataContract(code= DataCodes.CONTRACT)
+public interface ContractInfo extends AccountHeader {
+
+ @DataField(order=4, primitiveType= PrimitiveType.BYTES)
+ byte[] getChainCode();
+}
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
index 1b46f1aa..a9f47141 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainQueryService.java
@@ -296,7 +296,7 @@ public interface BlockchainQueryService {
* @param address
* @return
*/
- AccountHeader getContract(HashDigest ledgerHash, String address);
+ ContractInfo getContract(HashDigest ledgerHash, String address);
/**
* get users by ledgerHash and its range;
diff --git a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java
index d93f0f4f..2f8ec8e6 100644
--- a/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java
+++ b/source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/OperationResultHolder.java
@@ -11,7 +11,8 @@ abstract class OperationResultHolder implements OperationResultHandle {
private volatile boolean completed;
- private EventMulticaster listenerMulticaster;
+ private EventMulticaster listenerMulticaster =
+ new EventMulticaster<>(OperationCompletedListener.class);
/**
* 导致结束的错误;
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 01c2ef61..53f5b36e 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
@@ -3,6 +3,7 @@ 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;
@@ -13,19 +14,6 @@ import org.springframework.web.bind.annotation.RestController;
import com.jd.blockchain.contract.ContractException;
import com.jd.blockchain.crypto.HashDigest;
-import com.jd.blockchain.ledger.AccountHeader;
-import com.jd.blockchain.ledger.BytesValue;
-import com.jd.blockchain.ledger.KVDataEntry;
-import com.jd.blockchain.ledger.KVDataObject;
-import com.jd.blockchain.ledger.KVDataVO;
-import com.jd.blockchain.ledger.KVInfoVO;
-import com.jd.blockchain.ledger.LedgerBlock;
-import com.jd.blockchain.ledger.LedgerInfo;
-import com.jd.blockchain.ledger.LedgerMetadata;
-import com.jd.blockchain.ledger.LedgerTransaction;
-import com.jd.blockchain.ledger.ParticipantNode;
-import com.jd.blockchain.ledger.TransactionState;
-import com.jd.blockchain.ledger.UserInfo;
import com.jd.blockchain.ledger.core.ContractAccountSet;
import com.jd.blockchain.ledger.core.DataAccount;
import com.jd.blockchain.ledger.core.DataAccountSet;
@@ -454,8 +442,8 @@ public class LedgerQueryController implements BlockchainQueryService {
@RequestMapping(method = RequestMethod.GET, path = "ledgers/{ledgerHash}/contracts/address/{address}")
@Override
- public AccountHeader getContract(@PathVariable(name = "ledgerHash") HashDigest ledgerHash,
- @PathVariable(name = "address") String address) {
+ 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);
diff --git a/source/pom.xml b/source/pom.xml
index f8c9dfce..11ba5866 100644
--- a/source/pom.xml
+++ b/source/pom.xml
@@ -41,7 +41,7 @@
0.8.1-SNAPSHOT
0.0.8.RELEASE
- 0.6.6.RELEASE
+ 0.7.0.RELEASE
@@ -49,7 +49,7 @@
1.2.2
1.8.8
-
+ 0.5.35
1.0.18
1.2.2
1.2.4
@@ -112,8 +112,8 @@
com.jd.blockchain
- browser
- ${browser.version}
+ explorer
+ ${explorer.version}
@@ -147,6 +147,27 @@
${disruptor.version}
+
+ org.bitbucket.mstrobel
+ procyon-core
+ ${procyon.version}
+
+
+ org.bitbucket.mstrobel
+ procyon-expressions
+ ${procyon.version}
+
+
+ org.bitbucket.mstrobel
+ procyon-reflection
+ ${procyon.version}
+
+
+ org.bitbucket.mstrobel
+ procyon-compilertools
+ ${procyon.version}
+
+
com.alibaba
fastjson
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java
new file mode 100644
index 00000000..4a004b2b
--- /dev/null
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java
@@ -0,0 +1,64 @@
+package com.jd.blockchain.sdk;
+
+import com.jd.blockchain.crypto.HashDigest;
+import com.jd.blockchain.crypto.PubKey;
+import com.jd.blockchain.utils.Bytes;
+
+public class ContractSettings {
+
+ private Bytes address;
+
+ private PubKey pubKey;
+
+ private HashDigest rootHash;
+
+ private String chainCode;
+
+ public ContractSettings() {
+ }
+
+ public ContractSettings(Bytes address, PubKey pubKey, HashDigest rootHash) {
+ this.address = address;
+ this.pubKey = pubKey;
+ this.rootHash = rootHash;
+ }
+
+ public ContractSettings(Bytes address, PubKey pubKey, HashDigest rootHash, String chainCode) {
+ this.address = address;
+ this.pubKey = pubKey;
+ this.rootHash = rootHash;
+ this.chainCode = chainCode;
+ }
+
+ public Bytes getAddress() {
+ return address;
+ }
+
+ public void setAddress(Bytes address) {
+ this.address = address;
+ }
+
+ public PubKey getPubKey() {
+ return pubKey;
+ }
+
+ public void setPubKey(PubKey pubKey) {
+ this.pubKey = pubKey;
+ }
+
+ public HashDigest getRootHash() {
+ return rootHash;
+ }
+
+ public void setRootHash(HashDigest rootHash) {
+ this.rootHash = rootHash;
+ }
+
+ public String getChainCode() {
+ return chainCode;
+ }
+
+ public void setChainCode(String chainCode) {
+ this.chainCode = chainCode;
+ }
+}
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
index 4875def3..c850b57a 100644
--- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/BlockchainServiceProxy.java
@@ -167,7 +167,7 @@ public abstract class BlockchainServiceProxy implements BlockchainService {
}
@Override
- public AccountHeader getContract(HashDigest ledgerHash, String address) {
+ public ContractInfo getContract(HashDigest ledgerHash, String address) {
return getQueryService(ledgerHash).getContract(ledgerHash, address);
}
diff --git a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
index bd063a5d..838ad829 100644
--- a/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
+++ b/source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/proxy/HttpBlockchainQueryService.java
@@ -544,7 +544,7 @@ public interface HttpBlockchainQueryService extends BlockchainExtendQueryService
*/
@HttpAction(method=HttpMethod.GET, path="ledgers/{ledgerHash}/contracts/address/{address}")
@Override
- AccountHeader getContract(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash,
+ ContractInfo getContract(@PathParam(name="ledgerHash", converter=HashDigestToStringConverter.class) HashDigest ledgerHash,
@PathParam(name="address") String address);
diff --git a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
index d7daceaf..8e32d3df 100644
--- a/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
+++ b/source/tools/tools-mocker/src/main/java/com/jd/blockchain/mocker/MockerNodeContext.java
@@ -373,7 +373,7 @@ public class MockerNodeContext implements BlockchainQueryService {
}
@Override
- public AccountHeader getContract(HashDigest ledgerHash, String address) {
+ public ContractInfo getContract(HashDigest ledgerHash, String address) {
return queryService.getContract(ledgerHash, address);
}