From 867c0f691187def394cca27fcb42b279a481ef8e Mon Sep 17 00:00:00 2001 From: shaozhuguang Date: Thu, 20 Jun 2019 17:47:46 +0800 Subject: [PATCH] Add Contract Code Show ! --- .../service/classic/ClassicAlgorithm.java | 16 +- .../crypto/service/classic/EncodeTest.java | 18 ++ source/gateway/pom.xml | 19 +- .../decompiler/loads/BytesTypeLoader.java | 249 ++++++++++++++++++ .../decompiler/utils/DecompilerUtils.java | 218 +++++++++++++++ .../gateway/service/GatewayQueryService.java | 13 + .../service/GatewayQueryServiceHandler.java | 18 ++ .../gateway/web/BlockBrowserController.java | 16 +- .../ledger/core/ContractAccount.java | 3 +- .../ledger/core/impl/LedgerQueryService.java | 16 +- .../impl/handles/ContractLedgerContext.java | 20 +- .../jd/blockchain/ledger/ContractInfo.java | 13 + .../transaction/BlockchainQueryService.java | 2 +- .../transaction/OperationResultHolder.java | 3 +- .../peer/web/LedgerQueryController.java | 18 +- source/pom.xml | 29 +- .../jd/blockchain/sdk/ContractSettings.java | 64 +++++ .../sdk/proxy/BlockchainServiceProxy.java | 2 +- .../sdk/proxy/HttpBlockchainQueryService.java | 2 +- .../blockchain/mocker/MockerNodeContext.java | 2 +- 20 files changed, 674 insertions(+), 67 deletions(-) create mode 100644 source/crypto/crypto-classic/src/test/java/test/com/jd/blockchain/crypto/service/classic/EncodeTest.java create mode 100644 source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/loads/BytesTypeLoader.java create mode 100644 source/gateway/src/main/java/com/jd/blockchain/gateway/decompiler/utils/DecompilerUtils.java create mode 100644 source/ledger/ledger-model/src/main/java/com/jd/blockchain/ledger/ContractInfo.java create mode 100644 source/sdk/sdk-base/src/main/java/com/jd/blockchain/sdk/ContractSettings.java 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); }