Browse Source

Modify Contract Plugin's Check Function!

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
34c602991d
9 changed files with 337 additions and 4 deletions
  1. +1
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java
  2. +3
    -2
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractCheckMojo.java
  3. +227
    -0
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/ContractVerifyMojo.java
  4. +29
    -0
      source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java
  5. +8
    -2
      source/contract/contract-samples/pom.xml
  6. +7
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java
  7. +12
    -0
      source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java
  8. +8
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptService.java
  9. +42
    -0
      source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptServiceHandler.java

+ 1
- 0
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/CheckImportsMojo.java View File

@@ -42,6 +42,7 @@ import java.util.stream.Collectors;
*/
@Mojo(name = "checkImports")
public class CheckImportsMojo extends AbstractMojo {

Logger logger = LoggerFactory.getLogger(CheckImportsMojo.class);

@Parameter(defaultValue = "${project}", required = true, readonly = true)


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

@@ -141,7 +141,7 @@ public class ContractCheckMojo extends AbstractMojo {
pluginExecution.setId("make-assembly");
pluginExecution.setPhase("verify");
List <String> goals = new ArrayList<>();
goals.add("checkImports");
goals.add("JDChain.Verify");
pluginExecution.setGoals(goals);
List<PluginExecution> pluginExecutions = new ArrayList<>();
pluginExecutions.add(pluginExecution);
@@ -215,7 +215,8 @@ public class ContractCheckMojo extends AbstractMojo {
//将字节数组fileInput中的内容输出到文件fileOut.xml中;
ConsoleUtils.info(new String(buffer));
fos.write(buffer);
invokeCompile(fileOutput);
fos.flush();
fos.close();
invokeCompile(fileOutput);
}
}

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

@@ -0,0 +1,227 @@
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.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 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.Enumeration;
import java.util.List;
import java.util.Properties;
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;

/**
* first step, we want to parse the source code by javaParse. But it's repeated and difficult to parse the source.
* This is a try of "from Initail to Abandoned".
* Since we are good at the class, why not?
* Now we change a way of thinking, first we pre-compile the source code, then parse the *.jar.
*
* by zhaogw
* date 2019-06-05 16:17
*/
@Mojo(name = "JDChain.Verify")
public class ContractVerifyMojo extends AbstractMojo {

Logger logger = LoggerFactory.getLogger(ContractVerifyMojo.class);

private static final String JDCHAIN_META = "META-INF/JDCHAIN.TXT";

@Parameter(defaultValue = "${project}", required = true, readonly = true)
private MavenProject project;

/**
* jar's name;
*/
@Parameter
private String finalName;

@Override
public void execute() throws MojoFailureException {

List<Path> sources;
try {

File jarFile = copyAndManage();

InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties");
Properties properties = new Properties();
properties.load(inputStream);
String[] packageBlackList = properties.getProperty("blacklist").split(",");
Path baseDirPath = project.getBasedir().toPath();
sources = Files.find(baseDirPath, Integer.MAX_VALUE, (file, attrs) -> (file.toString().endsWith(".java"))).collect(Collectors.toList());
for (Path path : sources) {
CompilationUnit compilationUnit = JavaParser.parse(path);

compilationUnit.accept(new MethodVisitor(), null);

NodeList<ImportDeclaration> imports = compilationUnit.getImports();
for (ImportDeclaration imp : imports) {
String importName = imp.getName().asString();
for (String item : packageBlackList) {
if (importName.startsWith(item)) {
throw new MojoFailureException("在源码中不允许包含此引入包:" + importName);
}
}
}

//now we parse the jar;
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);
try {
Class mainClass = classLoader.loadClass(contractMainClass);
ContractType.resolve(mainClass);
} catch (ClassNotFoundException e) {
throw new IllegalDataException(e.getMessage());
}
}
} catch (IOException exception) {
logger.error(exception.getMessage());
throw new MojoFailureException("IO ERROR");
} catch (NullPointerException e) {
logger.error(e.getMessage());
}
}

private File copyAndManage() throws IOException {
// 首先将Jar包转换为指定的格式
String srcJarPath = project.getBuild().getDirectory() +
File.separator + finalName + ".jar";

String dstJarPath = project.getBuild().getDirectory() +
File.separator + finalName + "-temp-" + System.currentTimeMillis() + ".jar";

File srcJar = new File(srcJarPath), dstJar = new File(dstJarPath);

// 首先进行Copy处理
copy(srcJar, dstJar);

byte[] txtBytes = jdChainTxt(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, new JarEntry(JDCHAIN_META), txtBytes, null);

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

return finalJar;
// 删除srcJar

// 删除finalJar
// FileUtils.forceDelete(finalJar);
// // 删除srcJar
// srcJar.deleteOnExit();
//
// // 修改名字
// finalJar.renameTo(srcJar);
}

private void copy(File srcJar, File dstJar) throws IOException {
copy(srcJar, dstJar, null, null, null);
}

private void copy(File srcJar, File dstJar, JarEntry addEntry, byte[] addBytes, String filter) throws IOException {
JarFile jarFile = new JarFile(srcJar);
Enumeration<JarEntry> jarEntries = jarFile.entries();
JarOutputStream jarOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(dstJar)));

while(jarEntries.hasMoreElements()){
JarEntry jarEntry = jarEntries.nextElement();
String entryName = jarEntry.getName();
if (filter != null && filter.equals(entryName)) {
continue;
}
System.out.println(entryName);
jarOut.putNextEntry(jarEntry);
jarOut.write(readStream(jarFile.getInputStream(jarEntry)));
jarOut.closeEntry();
}
if (addEntry != null) {
jarOut.putNextEntry(addEntry);
jarOut.write(addBytes);
jarOut.closeEntry();
}

jarOut.flush();
jarOut.finish();
jarOut.close();
jarFile.close();
}

private String jdChainTxt(byte[] content) {
// hash=Hex(hash(content))
String hashTxt = "hash:" + DigestUtils.sha256Hex(content);
System.out.println(hashTxt);
return hashTxt;
}

private byte[] readStream(InputStream inputStream) {
try (ByteArrayOutputStream outSteam = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
inputStream.close();
return outSteam.toByteArray();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private class MethodVisitor extends VoidVisitorAdapter<Void> {
@Override
public void visit(MethodDeclaration n, Void arg) {
/* here you can access the attributes of the method.
this method will be called for all methods in this
CompilationUnit, including inner class methods */
logger.info("method:"+n.getName());
super.visit(n, arg);
}

@Override
public void visit(ClassOrInterfaceDeclaration n, Void arg) {
logger.info("class:"+n.getName()+" extends:"+n.getExtendedTypes()+" implements:"+n.getImplementedTypes());

super.visit(n, arg);
}

@Override
public void visit(PackageDeclaration n, Void arg) {
logger.info("package:"+n.getName());
super.visit(n, arg);
}

}
}

+ 29
- 0
source/contract/contract-maven-plugin/src/test/java/com/jd/blockchain/ledger/ContractVerifyMojoTest.java View File

@@ -0,0 +1,29 @@
package com.jd.blockchain.ledger;

import com.jd.blockchain.CheckImportsMojo;
import com.jd.blockchain.ContractVerifyMojo;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;

/**
* @Author zhaogw
* @Date 2019/3/1 21:27
*/
public class ContractVerifyMojoTest extends AbstractMojoTestCase {
Logger logger = LoggerFactory.getLogger(ContractVerifyMojoTest.class);

@Test
public void test1() throws Exception {
File pom = getTestFile( "src/test/resources/project-to-test/pom.xml" );
assertNotNull( pom );
assertTrue( pom.exists() );

ContractVerifyMojo myMojo = (ContractVerifyMojo) lookupMojo( "JDChain.Verify", pom );
assertNotNull( myMojo );
myMojo.execute();
}
}

+ 8
- 2
source/contract/contract-samples/pom.xml View File

@@ -27,6 +27,12 @@
<version>${project.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>

</dependencies>

<build>
@@ -34,11 +40,11 @@
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>transfer</finalName>
<finalName>complex</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>com.jd.blockchain.contract.TransferContractImpl</mainClass>
<mainClass>com.jd.blockchain.contract.ComplexContractImpl</mainClass>
</manifest>
</archive>
<descriptorRefs>


+ 7
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContract.java View File

@@ -0,0 +1,7 @@
package com.jd.blockchain.contract;

@Contract
public interface ComplexContract {
@ContractEvent(name = "read-key")
String read(String address, String key);
}

+ 12
- 0
source/contract/contract-samples/src/main/java/com/jd/blockchain/contract/ComplexContractImpl.java View File

@@ -0,0 +1,12 @@
package com.jd.blockchain.contract;


import com.alibaba.fastjson.JSON;

public class ComplexContractImpl implements ComplexContract {
@Override
public String read(String address, String key) {
String json = JSON.toJSONString(address);
return System.currentTimeMillis() + "" + json;
}
}

+ 8
- 0
source/gateway/src/main/java/com/jd/blockchain/gateway/service/GatewayInterceptService.java View File

@@ -0,0 +1,8 @@
package com.jd.blockchain.gateway.service;

import com.jd.blockchain.ledger.TransactionRequest;

public interface GatewayInterceptService {

void intercept(TransactionRequest txRequest);
}

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

@@ -0,0 +1,42 @@
package com.jd.blockchain.gateway.service;

import com.jd.blockchain.gateway.PeerService;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class GatewayInterceptServiceHandler implements GatewayInterceptService {

@Autowired
private PeerService peerService;

@Override
public void intercept(TransactionRequest txRequest) {
// 当前仅处理合约发布的请求
Operation[] operations = txRequest.getTransactionContent().getOperations();
if (operations != null && operations.length > 0) {
for (Operation op : operations) {
if (ContractCodeDeployOperation.class.isAssignableFrom(op.getClass())) {
// 发布合约请求
contractCheck((ContractCodeDeployOperation)op);
}
}
}
}

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




}
}

Loading…
Cancel
Save