Browse Source

修改合约打包验证功能模块

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
f08f6cc9cf
11 changed files with 87 additions and 87 deletions
  1. +23
    -23
      source/contract/contract-maven-plugin/pom.xml
  2. +10
    -10
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java
  3. +20
    -26
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java
  4. +3
    -3
      source/contract/contract-maven-plugin/src/main/resources/config.properties
  5. +1
    -1
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest.java
  6. +3
    -9
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java
  7. +7
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/web/TxProcessingController.java
  8. +6
    -2
      source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java
  9. +0
    -2
      source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java
  10. +12
    -9
      source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java
  11. +2
    -2
      source/utils/utils-common/src/test/java/test/my/utils/ContractJarUtilsTest.java

+ 23
- 23
source/contract/contract-maven-plugin/pom.xml View File

@@ -103,27 +103,27 @@
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<optimize>false</optimize>
<debug>true</debug>
<showDeprecation>false</showDeprecation>
<showWarnings>false</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<optimize>false</optimize>
<debug>true</debug>
<showDeprecation>false</showDeprecation>
<showWarnings>false</showWarnings>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>-->
</plugins>
</build>
</project>

+ 10
- 10
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java View File

@@ -1,6 +1,5 @@
package com.jd.blockchain;

import com.jd.blockchain.ledger.BlockchainKeyGenerator;
import org.apache.commons.io.FileUtils;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
@@ -8,6 +7,7 @@ import org.apache.maven.model.PluginExecution;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
@@ -22,11 +22,12 @@ import java.util.Collections;
import java.util.List;


@Mojo(name = "Contract.Check")
@Mojo(name = "contractCheck")
public class ContractCheckMojo extends AbstractMojo {

Logger LOG = LoggerFactory.getLogger(ContractCheckMojo.class);

public static final String CONTRACT_VERIFY = "Contract.Verify";
public static final String CONTRACT_VERIFY = "contractVerify";

private static final String CONTRACT_MAVEN_PLUGIN = "contract-maven-plugin";

@@ -36,11 +37,11 @@ public class ContractCheckMojo extends AbstractMojo {

private static final String APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins";

private static final String GOALS_VERIFY = "verify";
private static final String GOALS_VERIFY = "package";

private static final String GOALS_PACKAGE = "package";

private static final String OUT_POM_XML = "OutPom.xml";
private static final String OUT_POM_XML = "ContractPom.xml";

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;
@@ -51,7 +52,6 @@ public class ContractCheckMojo extends AbstractMojo {
@Parameter
private String finalName;


/**
* mainClass;
*/
@@ -73,11 +73,11 @@ public class ContractCheckMojo extends AbstractMojo {
* first compile the class, then parse it;
*/
@Override
public void execute() {
public void execute() throws MojoFailureException {
compileFiles();
}

private void compileFiles(){
private void compileFiles() throws MojoFailureException {
try (FileInputStream fis = new FileInputStream(project.getFile())) {

MavenXpp3Reader reader = new MavenXpp3Reader();
@@ -107,7 +107,7 @@ public class ContractCheckMojo extends AbstractMojo {

} catch (Exception e) {
LOG.error(e.getMessage());
throw new IllegalStateException(e);
throw new MojoFailureException(e.getMessage());
}
}

@@ -185,7 +185,7 @@ public class ContractCheckMojo extends AbstractMojo {
PluginExecution pluginExecution = new PluginExecution();
pluginExecution.setId(id);
pluginExecution.setPhase(phase);
List <String> goals = new ArrayList<>();
List<String> goals = new ArrayList<>();
goals.add(goal);
pluginExecution.setGoals(goals);
List<PluginExecution> pluginExecutions = new ArrayList<>();


+ 20
- 26
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java View File

@@ -3,37 +3,25 @@ package com.jd.blockchain;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.PackageDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.utils.IllegalDataException;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;

import static com.jd.blockchain.ContractCheckMojo.CONTRACT_VERIFY;
import static com.jd.blockchain.utils.decompiler.utils.DecompilerUtils.decompileJarFile;
@@ -78,12 +66,15 @@ public class ContractVerifyMojo extends AbstractMojo {
private static final String BLACK_NAME_LIST = "black.name.list";

@Override
public void execute() throws MojoFailureException {
public void execute() throws MojoExecutionException {

try {

File jarFile = copyAndManage();

// 首先校验MainClass
verifyMainClass(jarFile);

Properties config = loadConfig();

List<ContractPackage> blackNameList = blackNameList(config);
@@ -193,23 +184,25 @@ public class ContractVerifyMojo extends AbstractMojo {
if (!isOK) {
throw new IllegalStateException("There are many Illegal information, please check !!!");
}

// 加载main-class,开始校验类型
URL jarURL = jarFile.toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader());
Attributes m = new JarFile(jarFile).getManifest().getMainAttributes();
String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS);
Class mainClass = classLoader.loadClass(contractMainClass);
ContractType.resolve(mainClass);
} else {
throw new IllegalStateException("There is none class !!!");
}
} catch (Exception e) {
LOG.error(e.getMessage());
throw new MojoFailureException(e.getMessage());
throw new MojoExecutionException(e.getMessage());
}
}

private void verifyMainClass(File jarFile) throws Exception {
// 加载main-class,开始校验类型
URL jarURL = jarFile.toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader());
Attributes m = new JarFile(jarFile).getManifest().getMainAttributes();
String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS);
Class mainClass = classLoader.loadClass(contractMainClass);
ContractType.resolve(mainClass);
}

private List<ContractPackage> blackNameList(Properties config) {
return blackList(config, BLACK_NAME_LIST);
}
@@ -320,14 +313,14 @@ public class ContractVerifyMojo extends AbstractMojo {
// 首先进行Copy处理
copy(srcJar, dstJar);

byte[] txtBytes = jdChainTxt(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);
byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);

String finalJarPath = project.getBuild().getDirectory() +
File.separator + finalName + "-jdchain.jar";

File finalJar = new File(finalJarPath);

copy(dstJar, finalJar, jdChainMetaTxtJarEntry(), txtBytes, null);
copy(dstJar, finalJar, contractMFJarEntry(), txtBytes, null);

// 删除临时文件
FileUtils.forceDelete(dstJar);
@@ -423,8 +416,9 @@ public class ContractVerifyMojo extends AbstractMojo {
if (totalPackage.endsWith("*")) {
this.packageName = totalPackage.substring(0, totalPackage.length() - 2).trim();
this.isTotal = true;
} else {
this.packageName = totalPackage;
}
this.packageName = totalPackage;
}

public String getPackageName() {


+ 3
- 3
source/contract/contract-maven-plugin/src/main/resources/config.properties View File

@@ -1,8 +1,8 @@
#black.name.list:打包为合约Jar后,每个Class文件不允许使用的名称,默认不允许使用com.jd.blockchain.*
black.name.list=com.jd.blockchain.*
#black.name.list:打包为合约Jar后,每个Class文件不允许使用或包含的名称,默认不允许使用com.jd.blockchain.*及一些内部已经引用的包
black.name.list=com.jd.blockchain.*, com.alibaba.fastjson.*, org.apache.commons.io.*, org.apache.commons.codec.*, io.netty.*

#black.package.list:打包为合约中的每个Class都不允许使用的包列表,某个包下面的所有包通过.*表示
black.package.list=java.io.*, java.net.*, org.apache.commons.io.*
black.package.list=java.io.*, java.nio.*, java.net.*, org.apache.commons.io.*

#black.class.list:打包为合约中的每个Class都不允许使用的类列表
black.class.list=java.util.Random, com.jd.blockchain.ledger.BlockchainKeyGenerator

+ 1
- 1
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyTest.java View File

@@ -18,7 +18,7 @@ public class ContractVerifyTest {
@Before
public void testInit() {
project = mavenProjectInit();
finalName = "complex.jar";
finalName = "complex";
}

@Test


+ 3
- 9
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java View File

@@ -5,6 +5,7 @@ import com.jd.blockchain.ledger.ContractCodeDeployOperation;
import com.jd.blockchain.ledger.Operation;
import com.jd.blockchain.ledger.TransactionRequest;
import com.jd.blockchain.utils.IllegalDataException;
import com.jd.blockchain.utils.jar.ContractJarUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@@ -29,14 +30,7 @@ public class GatewayInterceptServiceHandler implements GatewayInterceptService {
}

private void contractCheck(final ContractCodeDeployOperation contractOP) {
//
byte[] chainCode = contractOP.getChainCode();
if (chainCode == null || chainCode.length == 0) {
throw new IllegalDataException("Contract's content is empty !!!");
}




// 校验chainCode
ContractJarUtils.verify(contractOP.getChainCode());
}
}

+ 7
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/web/TxProcessingController.java View File

@@ -1,5 +1,6 @@
package com.jd.blockchain.gateway.web;

import com.jd.blockchain.gateway.service.GatewayInterceptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -30,9 +31,15 @@ public class TxProcessingController implements TransactionService {
@Autowired
private PeerService peerService;

@Autowired
private GatewayInterceptService interceptService;

@RequestMapping(path = "rpc/tx", method = RequestMethod.POST, consumes = BinaryMessageConverter.CONTENT_TYPE_VALUE, produces = BinaryMessageConverter.CONTENT_TYPE_VALUE)
@Override
public @ResponseBody TransactionResponse process(@RequestBody TransactionRequest txRequest) {
// 拦截请求进行校验
interceptService.intercept(txRequest);

// 检查交易请求的信息是否完整;
HashDigest ledgerHash = txRequest.getTransactionContent().getLedgerHash();
if (ledgerHash == null) {


+ 6
- 2
source/ledger/ledger-core/src/main/java/com/jd/blockchain/ledger/core/impl/handles/ContractCodeDeployOperationHandle.java View File

@@ -1,5 +1,6 @@
package com.jd.blockchain.ledger.core.impl.handles;

import com.jd.blockchain.utils.jar.ContractJarUtils;
import org.springframework.stereotype.Service;

import com.jd.blockchain.ledger.BytesValue;
@@ -22,8 +23,12 @@ public class ContractCodeDeployOperationHandle implements OperationHandle {
// TODO: 请求者应该提供合约账户的公钥签名,已确定注册的地址的唯一性;

byte[] chainCode = contractOP.getChainCode();
// 校验合约代码,不通过会抛出异常
ContractJarUtils.verify(chainCode);

dataset.getContractAccountSet().deploy(contractOP.getContractID().getAddress(),
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), contractOP.getChainCode());
contractOP.getContractID().getPubKey(), contractOP.getAddressSignature(), chainCode);

return null;
}
@@ -37,5 +42,4 @@ public class ContractCodeDeployOperationHandle implements OperationHandle {
public boolean support(Class<?> operationType) {
return ContractCodeDeployOperation.class.isAssignableFrom(operationType);
}

}

+ 0
- 2
source/ledger/ledger-model/src/main/java/com/jd/blockchain/transaction/BlockchainOperationFactory.java View File

@@ -260,8 +260,6 @@ public class BlockchainOperationFactory implements ClientOperator, LedgerInitOpe
private class ContractCodeDeployOperationBuilderFilter implements ContractCodeDeployOperationBuilder {
@Override
public ContractCodeDeployOperation deploy(BlockchainIdentity id, byte[] chainCode) {
// 校验chainCode
ContractJarUtils.verify(chainCode);
// 校验成功后发布
ContractCodeDeployOperation op = CONTRACT_CODE_DEPLOY_OP_BUILDER.deploy(id, chainCode);
operationList.add(op);


+ 12
- 9
source/utils/utils-common/src/main/java/com/jd/blockchain/utils/jar/ContractJarUtils.java View File

@@ -15,13 +15,16 @@ import java.util.jar.JarOutputStream;

public class ContractJarUtils {

private static final String JDCHAIN_META = "META-INF/CONTRACT.MF";
private static final String CONTRACT_MF = "META-INF/CONTRACT.MF";

private static final int JDCHAIN_HASH_LENGTH = 69;

private static final Random FILE_RANDOM = new Random();

public static void verify(byte[] chainCode) {
if (chainCode == null || chainCode.length == 0) {
throw new IllegalStateException("ChainCode is empty !!!");
}
// 首先生成合约文件
File jarFile = newJarFile();
try {
@@ -42,14 +45,14 @@ public class ContractJarUtils {

private static void verify(File jarFile) throws Exception {
// 首先判断jarFile中是否含有META-INF/JDCHAIN.TXT,并将其读出
URL jarUrl = new URL("jar:file:" + jarFile.getPath() + "!/" + JDCHAIN_META);
URL jarUrl = new URL("jar:file:" + jarFile.getPath() + "!/" + CONTRACT_MF);
InputStream inputStream = jarUrl.openStream();
if (inputStream == null) {
throw new IllegalStateException(JDCHAIN_META + " IS NULL !!!");
throw new IllegalStateException(CONTRACT_MF + " IS NULL !!!");
}
byte[] bytes = IOUtils.toByteArray(inputStream);
if (bytes == null || bytes.length != JDCHAIN_HASH_LENGTH) {
throw new IllegalStateException(JDCHAIN_META + " IS Illegal !!!");
throw new IllegalStateException(CONTRACT_MF + " IS Illegal !!!");
}
// 获取对应的Hash内容
String txt = new String(bytes, StandardCharsets.UTF_8);
@@ -58,10 +61,10 @@ public class ContractJarUtils {
File tempJar = newJarFile();

// 复制除JDCHAIN.TXT之外的部分
copy(jarFile, tempJar, null, null, JDCHAIN_META);
copy(jarFile, tempJar, null, null, CONTRACT_MF);

// 生成新Jar包对应的Hash内容
String verifyTxt = jdChainTxt(FileUtils.readFileToByteArray(tempJar));
String verifyTxt = contractMF(FileUtils.readFileToByteArray(tempJar));

// 删除临时文件
FileUtils.forceDelete(tempJar);
@@ -103,13 +106,13 @@ public class ContractJarUtils {
jarFile.close();
}

public static String jdChainTxt(byte[] content) {
public static String contractMF(byte[] content) {
// hash=Hex(hash(content))
return "hash:" + DigestUtils.sha256Hex(content);
}

public static JarEntry jdChainMetaTxtJarEntry() {
return new JarEntry(JDCHAIN_META);
public static JarEntry contractMFJarEntry() {
return new JarEntry(CONTRACT_MF);
}

private static byte[] readStream(InputStream inputStream) {


+ 2
- 2
source/utils/utils-common/src/test/java/test/my/utils/ContractJarUtilsTest.java View File

@@ -34,14 +34,14 @@ public class ContractJarUtilsTest {
// 首先进行Copy处理
copy(srcJar, dstJar);

byte[] txtBytes = jdChainTxt(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);
byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8);

String finalJarPath = classPath +
File.separator + jarName + "-jdchain.jar";

File finalJar = new File(finalJarPath);

copy(dstJar, finalJar, jdChainMetaTxtJarEntry(), txtBytes, null);
copy(dstJar, finalJar, contractMFJarEntry(), txtBytes, null);

// 删除临时文件
FileUtils.forceDelete(dstJar);


Loading…
Cancel
Save