| @@ -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); | |||
| @@ -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) | |||
| } | |||
| } | |||
| @@ -45,7 +45,7 @@ | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>browser</artifactId> | |||
| <artifactId>explorer</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| @@ -78,6 +78,23 @@ | |||
| <version>${commons-io.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-core</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-expressions</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-reflection</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-compilertools</artifactId> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.springframework.boot</groupId> | |||
| <artifactId>spring-boot-starter-web</artifactId> | |||
| @@ -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<String, LinkedHashSet<byte[]>> packageLocations; | |||
| private final Map<String, byte[]> 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<byte[]> 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<byte[]> 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; | |||
| } | |||
| } | |||
| @@ -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<String> 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<String> 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(); | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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; | |||
| } | |||
| /** | |||
| * 初始化账本配置 | |||
| * | |||
| @@ -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" + "'}"; | |||
| @@ -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); | |||
| @@ -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); | |||
| @@ -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); | |||
| } | |||
| @@ -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(); | |||
| } | |||
| @@ -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; | |||
| @@ -11,7 +11,8 @@ abstract class OperationResultHolder implements OperationResultHandle { | |||
| private volatile boolean completed; | |||
| private EventMulticaster<OperationCompletedListener> listenerMulticaster; | |||
| private EventMulticaster<OperationCompletedListener> listenerMulticaster = | |||
| new EventMulticaster<>(OperationCompletedListener.class); | |||
| /** | |||
| * 导致结束的错误; | |||
| @@ -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); | |||
| @@ -41,7 +41,7 @@ | |||
| <properties> | |||
| <my.utils.version>0.8.1-SNAPSHOT</my.utils.version> | |||
| <bft-smart.version>0.0.8.RELEASE</bft-smart.version> | |||
| <browser.version>0.6.6.RELEASE</browser.version> | |||
| <explorer.version>0.7.0.RELEASE</explorer.version> | |||
| <!-- <spring.framework.version>4.3.4.RELEASE</spring.framework.version> --> | |||
| <!-- <spring.mongo.version>1.9.3.RELEASE</spring.mongo.version> <spring.dao.version>2.0.8</spring.dao.version> | |||
| <spring.security.version>4.2.0.RELEASE</spring.security.version> --> | |||
| @@ -49,7 +49,7 @@ | |||
| <shiro.version>1.2.2</shiro.version> | |||
| <aspectj.version>1.8.8</aspectj.version> | |||
| <!-- <asm.version>5.2</asm.version> --> | |||
| <procyon.version>0.5.35</procyon.version> | |||
| <druid.version>1.0.18</druid.version> | |||
| <commons.fileupload.version>1.2.2</commons.fileupload.version> | |||
| <mybatis.spring.version>1.2.4</mybatis.spring.version> | |||
| @@ -112,8 +112,8 @@ | |||
| <dependency> | |||
| <groupId>com.jd.blockchain</groupId> | |||
| <artifactId>browser</artifactId> | |||
| <version>${browser.version}</version> | |||
| <artifactId>explorer</artifactId> | |||
| <version>${explorer.version}</version> | |||
| </dependency> | |||
| <!-- The test dependency --> | |||
| @@ -147,6 +147,27 @@ | |||
| <version>${disruptor.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-core</artifactId> | |||
| <version>${procyon.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-expressions</artifactId> | |||
| <version>${procyon.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-reflection</artifactId> | |||
| <version>${procyon.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.bitbucket.mstrobel</groupId> | |||
| <artifactId>procyon-compilertools</artifactId> | |||
| <version>${procyon.version}</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.alibaba</groupId> | |||
| <artifactId>fastjson</artifactId> | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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); | |||
| } | |||
| @@ -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); | |||
| @@ -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); | |||
| } | |||