Browse Source

修正合约编译插件BUG

tags/1.1.0
shaozhuguang 5 years ago
parent
commit
e1b4240d51
11 changed files with 243 additions and 136 deletions
  1. +151
    -35
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractCompileMojo.java
  2. +2
    -1
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/BlackList.java
  3. +3
    -3
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/DependencyExclude.java
  4. +53
    -17
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/ResolveEngine.java
  5. +12
    -4
      source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/VerifyEngine.java
  6. +10
    -2
      source/contract/contract-maven-plugin/src/main/resources/blacks.conf
  7. +0
    -0
      source/contract/contract-maven-plugin/src/main/resources/providers.conf
  8. +3
    -1
      source/contract/contract-maven-plugin/src/main/resources/whites.conf
  9. +9
    -4
      source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java
  10. BIN
      source/ledger/ledger-core/src/test/resources/contract-JDChain-Contract.jar
  11. +0
    -69
      source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractJarUtilsTest.java

+ 151
- 35
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/ContractCompileMojo.java View File

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

import com.jd.blockchain.contract.ContractJarUtils;
import com.jd.blockchain.contract.maven.rule.BlackList;
import com.jd.blockchain.contract.maven.rule.WhiteList;
import com.jd.blockchain.contract.maven.rule.DependencyExclude;
import com.jd.blockchain.contract.maven.verify.ResolveEngine;
import com.jd.blockchain.contract.maven.verify.VerifyEngine;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@@ -16,8 +16,14 @@ import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static com.jd.blockchain.contract.ContractJarUtils.BLACK_CONF;
import static com.jd.blockchain.contract.ContractJarUtils.WHITE_CONF;

@Mojo(name = "compile")
public class ContractCompileMojo extends SingleAssemblyMojo {

@@ -42,46 +48,122 @@ public class ContractCompileMojo extends SingleAssemblyMojo {
// 首先对MainClass进行校验,要求必须有MainClass
String mainClass = mainClassVerify();

// 将JDChain本身代码之外的代码移除(不打包进整个Jar)
// 排除所有依赖,只打包当前代码
// excludeAllArtifactExclude(super.getProject().getDependencyArtifacts());
// handleArtifactCompile(super.getProject().getDependencyArtifacts());
handleArtifactExclude(super.getProject().getDependencyArtifacts());

// 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});

// 执行打包命令
// 该命令生成的是只含有当前项目的实际代码的Jar包,该Jar包仅用于校验MainClass
super.execute();

// 将本次打包好的文件重新命名,以便于后续重新打包需要
// 把文件改名,然后重新再生成一个文件
File dstFile;
// 生成解析引擎
ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass);

// 获取本次生成的Jar文件
File defaultJarFile;
try {
dstFile = rename(getProject(), getFinalName());
} catch (IOException e) {
defaultJarFile = rename(getProject(), getFinalName());
// 校验当前MainClass是否满足需求
resolveEngine.verifyCurrentProjectMainClass(defaultJarFile);
// 校验完成后将该Jar删除
// FileUtils.forceDelete(mainClassFile);
} catch (Exception e) {
getLog().error(e);
throw new MojoFailureException(e.getMessage());
}

// 首先校验该类的Jar包中是否包含不符合规范的命名,以及该类的代码中的部分解析
File finalJarFile = verify(dstFile, mainClass);

// 将所有的依赖的jar包全部打包进一个包中,以便于进行ASM检查
handleArtifactCompile(super.getProject().getDependencyArtifacts());

// 然后再打包一次,本次打包完成后,其中的代码包含所有的class(JDK自身的除外)
super.execute();

// 对代码中的一些规则进行校验,主要是校验其是否包含一些不允许使用的类、包、方法等
verify(mainClass);

// 删除中间的一些文件
// // 将JDChain本身之外的代码打包进Jar包,然后编译
// handleArtifactExclude(super.getProject().getDependencyArtifacts());
//
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});
//
// // 生成Jar包(该Jar包中不包含JDChain内部的代码)
// super.execute();
//
// File defaultJarFile;
// try {
// defaultJarFile = rename(getProject(), getFinalName());
// } catch (Exception e) {
// getLog().error(e);
// throw new MojoFailureException(e.getMessage());
// }

// 校验该Jar包
verify(defaultJarFile, mainClass);

File deployJarFile = resolveEngine.verify(defaultJarFile);

// 删除中间产生的临时文件
try {
FileUtils.forceDelete(dstFile);
} catch (IOException e) {
throw new MojoFailureException(e.getMessage());
FileUtils.forceDelete(defaultJarFile);
} catch (Exception e) {
getLog().error(e);
}

getLog().info(String.format("JDChain's Contract compile success, path = %s !", deployJarFile.getPath()));



// // 将JDChain本身代码之外的代码移除(不打包进整个Jar)
// handleArtifactExclude(super.getProject().getDependencyArtifacts());
//
// // 此参数用于设置将所有第三方依赖的Jar包打散为.class,与主代码打包在一起,生成一个jar包
// super.setDescriptorRefs(new String[]{JAR_DEPENDENCE});
//
// // 执行打包命令
// super.execute();

// // 将本次打包好的文件重新命名,以便于后续重新打包需要
// // 把文件改名,然后重新再生成一个文件
// File dstFile;
// try {
// dstFile = rename(getProject(), getFinalName());
// } catch (IOException e) {
// getLog().error(e);
// throw new MojoFailureException(e.getMessage());
// }
//
// // dstFile理论上应该含有
//
// // 首先校验该类的Jar包中是否包含不符合规范的命名,以及该类的代码中的部分解析
//
// ResolveEngine resolveEngine = new ResolveEngine(getLog(), mainClass);
//
// // 校验mainClass
// resolveEngine.verifyCurrentProjectMainClass(dstFile);
//
//
//
// File finalJarFile = resolveEngine.verify();
//
// // 将所有的依赖的jar包全部打包进一个包中,以便于进行ASM检查
// handleArtifactCompile(super.getProject().getDependencyArtifacts());
//
// // 然后再打包一次,本次打包完成后,其中的代码包含所有的class(JDK自身的除外)
// super.execute();
//
// File jarFile = new File(jarPath(getProject(), getFinalName()));
//
// // 校验mainClass
// resolveEngine.verifyCurrentProjectMainClass(jarFile);
//
// // 对代码中的一些规则进行校验,主要是校验其是否包含一些不允许使用的类、包、方法等
// verify(jarFile, mainClass);
//
// // 删除中间的一些文件
//// try {
//// FileUtils.forceDelete(dstFile);
//// } catch (IOException e) {
//// throw new MojoFailureException(e.getMessage());
//// }
//
// 若执行到此处没有异常则表明打包成功,打印打包成功消息
getLog().info(String.format("JDChain's Contract compile success, path = %s !", finalJarFile.getPath()));
// getLog().info(String.format("JDChain's Contract compile success, path = %s !", finalJarFile.getPath()));
}

private String mainClassVerify() throws MojoFailureException {
@@ -107,10 +189,20 @@ public class ContractCompileMojo extends SingleAssemblyMojo {
getLog().info(String.format("GroupId[%s] ArtifactId[%s] belongs to DependencyExclude !!!", groupId, artifactId));
// 属于排除的名单之中
artifact.setScope(SCOPE_PROVIDED);
} else {
getLog().info(String.format("GroupId[%s] ArtifactId[%s] not belongs to DependencyExclude !!!", groupId, artifactId));
// 属于排除的名单之中
artifact.setScope(SCOPE_COMPILE);
}
}
}

private void excludeAllArtifactExclude(Set<Artifact> artifacts) {
for (Artifact artifact : artifacts) {
artifact.setScope(SCOPE_PROVIDED);
}
}

private void handleArtifactCompile(Set<Artifact> artifacts) {
for (Artifact artifact : artifacts) {
if (artifact.getScope().equals(SCOPE_PROVIDED)) {
@@ -135,17 +227,14 @@ public class ContractCompileMojo extends SingleAssemblyMojo {
File.separator + finalName + "-" + JAR_DEPENDENCE + ".jar";
}

private void verify(String mainClass) throws MojoFailureException {
private void verify(File jarFile, String mainClass) throws MojoFailureException {
try {

File jarFile = new File(jarPath(getProject(), getFinalName()));

VerifyEngine verifyEngine = new VerifyEngine(getLog(), jarFile, mainClass, black, white);

verifyEngine.verify();

// 校验完成后将该jar包删除
FileUtils.forceDelete(jarFile);
// FileUtils.forceDelete(jarFile);

} catch (Exception e) {
getLog().error(e);
@@ -153,20 +242,47 @@ public class ContractCompileMojo extends SingleAssemblyMojo {
}
}

private File verify(File jarFile, String mainClass) throws MojoFailureException {

ResolveEngine resolveEngine = new ResolveEngine(getLog(), jarFile, mainClass);

return resolveEngine.verify();
private static void init() {
try {
black = AbstractContract.initBlack(loadBlackConf());
white = AbstractContract.initWhite(loadWhiteConf());
} catch (Exception e) {
throw new IllegalStateException(e);
}
}

private static List<String> loadWhiteConf() {

return resolveConfig(WHITE_CONF);
}

private static void init() {
private static List<String> loadBlackConf() {
return resolveConfig(BLACK_CONF);
}

private static List<String> resolveConfig(String fileName) {
List<String> configs = new ArrayList<>();

try {
black = AbstractContract.initBlack(ContractJarUtils.loadBlackConf());
white = AbstractContract.initWhite(ContractJarUtils.loadWhiteConf());
List<String> readLines = loadConfig(fileName);
if (!readLines.isEmpty()) {
for (String readLine : readLines) {
String[] lines = readLine.split(",");
configs.addAll(Arrays.asList(lines));
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
}

return configs;
}

public static List<String> loadConfig(String fileName) throws Exception {

return IOUtils.readLines(
ContractCompileMojo.class.getResourceAsStream("/" + fileName));
}
}

+ 2
- 1
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/rule/BlackList.java View File

@@ -52,6 +52,7 @@ public class BlackList {
}

public boolean isBlack(Class<?> clazz, String methodName) {

// 判断该Class是否属于黑名单
if (isCurrentClassBlack(clazz, methodName)) {
return true;
@@ -75,7 +76,7 @@ public class BlackList {

String packageName = clazz.getPackage().getName();
for (String bp : blackPackages) {
if (packageName.equals(bp) || packageName.startsWith(bp)) {
if ((packageName + ".").equals(bp) || packageName.startsWith(bp)) {
return true;
}
}


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

@@ -1,6 +1,6 @@
package com.jd.blockchain.contract.maven.rule;

import com.jd.blockchain.contract.ContractJarUtils;
import com.jd.blockchain.contract.maven.ContractCompileMojo;

import java.util.ArrayList;
import java.util.List;
@@ -11,7 +11,7 @@ public class DependencyExclude {

private static final String COMMON_ARTIFACTID = "*";

private static final String CONFIG = "provided.conf";
private static final String CONFIG = "providers.conf";

private static final Map<String, List<Dependency>> DEPENDENCYS = new ConcurrentHashMap<>();

@@ -24,7 +24,7 @@ public class DependencyExclude {
}

private static void init() throws Exception {
List<String> readLines = ContractJarUtils.loadConfig(CONFIG);
List<String> readLines = ContractCompileMojo.loadConfig(CONFIG);
if (!readLines.isEmpty()) {
for (String line : readLines) {
// groupId/artifactId


+ 53
- 17
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/ResolveEngine.java View File

@@ -1,7 +1,10 @@
package com.jd.blockchain.contract.maven.verify;

import com.alibaba.fastjson.JSON;
import com.jd.blockchain.contract.Contract;
import com.jd.blockchain.contract.ContractJarUtils;
import com.jd.blockchain.contract.ContractType;
import com.jd.blockchain.contract.EventProcessingAware;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
@@ -21,23 +24,49 @@ public class ResolveEngine {

private Log LOGGER;

private File jarFile;
// private File jarFile;

private String mainClass;

public ResolveEngine(Log LOGGER, File jarFile, String mainClass) {
// public ResolveEngine(Log LOGGER, File jarFile, String mainClass) {
public ResolveEngine(Log LOGGER, String mainClass) {
this.LOGGER = LOGGER;
this.jarFile = jarFile;
// this.jarFile = jarFile;
this.mainClass = mainClass;
}

public File verify() throws MojoFailureException {
/**
* 校验当前项目中MainClass其是否满足JDChain合约写法
*
* @param mainClassJarFile
* @throws MojoFailureException
*/
public void verifyCurrentProjectMainClass(File mainClassJarFile) throws MojoFailureException {
// 校验MainClass
try {
// 首先校验MainClass
ClassLoader classLoader = verifyMainClass(jarFile);
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass start...", mainClassJarFile.getName()));
// 自定义ClassLoader,必须使用Thread.currentThread().getContextClassLoader()
// 保证其项目内部加载的Jar包无须再加载一次
URLClassLoader classLoader = new URLClassLoader(new URL[]{mainClassJarFile.toURI().toURL()},
Thread.currentThread().getContextClassLoader());

// 从MainClass作为入口进行MainClass代码校验
Class<?> mClass = classLoader.loadClass(mainClass);
ContractType.resolve(mClass);

// 校验完成后需要释放,否则无法删除该Jar文件
classLoader.close();

LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", mainClassJarFile.getName()));
} catch (Exception e) {
throw new MojoFailureException(e.getMessage());
}
}

public File verify(File defaultJarFile) throws MojoFailureException {
try {
// 检查jar包中所有的class的命名,要求其包名不能为com.jd.blockchain.*
LinkedList<String> totalClasses = loadAllClass(jarFile);
LinkedList<String> totalClasses = loadAllClass(defaultJarFile);

if (!totalClasses.isEmpty()) {

@@ -47,9 +76,8 @@ public class ResolveEngine {

LOGGER.debug(String.format("Verify Dependency Class[%s] start......", dotClassName));
// 获取其包名
Class<?> currentClass = classLoader.loadClass(dotClassName);

String packageName = currentClass.getPackage().getName();
// 将class转换为包名
String packageName = class2Package(dotClassName);

if (ContractJarUtils.isJDChainPackage(packageName)) {
throw new IllegalStateException(String.format("Class[%s]'s package[%s] cannot start with %s !",
@@ -61,18 +89,23 @@ public class ResolveEngine {
}

// 处理完成之后,生成finalName-JDChain-Contract.jar
return compileCustomJar();
return compileCustomJar(defaultJarFile);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw new MojoFailureException(e.getMessage());
}
}

private File compileCustomJar() throws IOException {
private String class2Package(String dotClassName) {

return dotClassName.substring(0, dotClassName.lastIndexOf("."));
}

private File compileCustomJar(File defaultJarFile) throws IOException {

String fileParentPath = jarFile.getParentFile().getPath();
String fileParentPath = defaultJarFile.getParentFile().getPath();

String jarFileName = jarFile.getName();
String jarFileName = defaultJarFile.getName();

String fileName = jarFileName.substring(0, jarFileName.lastIndexOf("."));

@@ -80,13 +113,13 @@ public class ResolveEngine {
String dstJarPath = fileParentPath + File.separator +
fileName + "-temp-" + System.currentTimeMillis() + ".jar";

File srcJar = jarFile, dstJar = new File(dstJarPath);
File srcJar = defaultJarFile, dstJar = new File(dstJarPath);

LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", jarFile.getPath(), dstJarPath));
LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", defaultJarFile.getPath(), dstJarPath));
// 首先进行Copy处理
copy(srcJar, dstJar);

LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", jarFile.getPath(), dstJarPath));
LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", defaultJarFile.getPath(), dstJarPath));

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

@@ -128,6 +161,9 @@ public class ResolveEngine {
}
}
}
// Jar文件使用完成后需要关闭,否则可能会产生无法删除的问题
jarFile.close();

return allClass;
}
}

+ 12
- 4
source/contract/contract-maven-plugin/src/main/java/com/jd/blockchain/contract/maven/verify/VerifyEngine.java View File

@@ -52,7 +52,8 @@ public class VerifyEngine {
// 加载所有的jar,然后ASM获取MAP
URL jarURL = jarFile.toURI().toURL();

URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarURL});
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{jarURL},
Thread.currentThread().getContextClassLoader());

// 解析Jar包中所有的Class
Map<String, ContractClass> allContractClasses = resolveClasses(jarClasses());
@@ -60,6 +61,8 @@ public class VerifyEngine {
// 开始处理MainClass
verify(urlClassLoader, allContractClasses);

// 校验完成后需要释放ClassLoader,否则无法删除该Jar包
urlClassLoader.close();
}

public void verify(URLClassLoader urlClassLoader, Map<String, ContractClass> allContractClasses) throws Exception {
@@ -91,6 +94,8 @@ public class VerifyEngine {
// 将该方法设置为已处理
haveManagedMethods.add(managedKey);
String dotClassName = method.getDotClassName();


Class<?> dotClass = urlClassLoader.loadClass(dotClassName);

if (dotClass == null) {
@@ -137,8 +142,13 @@ public class VerifyEngine {
}
} else {
// 非URLClassLoader加载的类,只需要做判断即可
// 对于系统加载的类,其白名单优先级高于黑名单
// 1、不再需要获取其方法;
// 2、只需要判断黑名单不需要判断白名单
// 首先判断是否为白名单
if (white.isWhite(dotClass)) {
return;
}
// 然后判断其是否为黑名单
if (black.isBlack(dotClass, method.getMethodName())) {
throw new IllegalStateException(String.format("Class [%s] Method [%s] is Black !!!", dotClassName, method.getMethodName()));
}
@@ -187,8 +197,6 @@ public class VerifyEngine {
continue;
}

LOGGER.info(String.format("Resolve Class [%s] ...", className));

ContractClass contractClass = new ContractClass(className);
ClassReader cr = new ClassReader(classContent);
cr.accept(new ASMClassVisitor(contractClass), ClassReader.SKIP_DEBUG);


+ 10
- 2
source/contract/contract-maven-plugin/src/main/resources/blacks.conf View File

@@ -1,5 +1,13 @@
java.io.*
java.nio.*
java.io.File
java.io.InputStream
java.io.OutputStream
java.io.DataInput
java.io.DataOutput
java.io.Reader
java.io.Writer
java.io.Flushable
java.nio.channels.*
java.nio.file.*
java.net.*
java.sql.*
java.lang.reflect.*


source/contract/contract-maven-plugin/src/main/resources/provideds.conf → source/contract/contract-maven-plugin/src/main/resources/providers.conf View File


+ 3
- 1
source/contract/contract-maven-plugin/src/main/resources/whites.conf View File

@@ -1 +1,3 @@
com.jd.blockchain.*
com.jd.blockchain.*
java.nio.charset.Charset
com.alibaba.fastjson.*

+ 9
- 4
source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/ContractInvokingTest.java View File

@@ -13,9 +13,13 @@ import com.jd.blockchain.service.TransactionBatchResultHandle;
import com.jd.blockchain.storage.service.utils.MemoryKVStorage;
import com.jd.blockchain.transaction.TxBuilder;
import com.jd.blockchain.utils.Bytes;
import com.jd.blockchain.utils.io.BytesUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.mockito.Mockito;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Random;

import static org.junit.Assert.*;
@@ -44,6 +48,9 @@ public class ContractInvokingTest {
// 采用基于内存的 Storage;
private MemoryKVStorage storage = new MemoryKVStorage();

// 用于测试的发布合约文件
private static final String CONTRACT_JAR = "contract-JDChain-Contract.jar";

@Test
public void test() {
// 初始化账本到指定的存储库;
@@ -82,7 +89,6 @@ public class ContractInvokingTest {
// 构建基于接口调用合约的交易请求,用于测试合约调用;
TxBuilder txBuilder = new TxBuilder(ledgerHash);
TestContract contractProxy = txBuilder.contract(contractAddress, TestContract.class);
TestContract contractProxy1 = txBuilder.contract(contractAddress, TestContract.class);

String asset = "AK";
long issueAmount = new Random().nextLong();
@@ -190,8 +196,7 @@ public class ContractInvokingTest {
}

private byte[] chainCode() {
byte[] chainCode = new byte[1024];
new Random().nextBytes(chainCode);
return chainCode;

return BytesUtils.copyToBytes(this.getClass().getResourceAsStream("/" + CONTRACT_JAR));
}
}

BIN
source/ledger/ledger-core/src/test/resources/contract-JDChain-Contract.jar View File


+ 0
- 69
source/ledger/ledger-model/src/test/java/test/com/jd/blockchain/ledger/data/ContractJarUtilsTest.java View File

@@ -1,69 +0,0 @@
package test.com.jd.blockchain.ledger.data;

import org.apache.commons.io.FileUtils;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;

import java.io.File;
import java.nio.charset.StandardCharsets;

import static com.jd.blockchain.contract.ContractJarUtils.*;
import static org.junit.Assert.fail;

public class ContractJarUtilsTest {

private String jarName = "complex";

@Test
public void test() {

byte[] chainCode = null;
try {
ClassPathResource classPathResource = new ClassPathResource(jarName + ".jar");
String classPath = classPathResource.getFile().getParentFile().getPath();

// 首先将Jar包转换为指定的格式
String srcJarPath = classPath +
File.separator + jarName + ".jar";

String dstJarPath = classPath +
File.separator + jarName + "-temp-" + System.currentTimeMillis() + ".jar";

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

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

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, contractMFJarEntry(), txtBytes, null);

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

// 读取finalJar中的内容
chainCode = FileUtils.readFileToByteArray(finalJar);

FileUtils.forceDelete(finalJar);
} catch (Exception e) {
e.printStackTrace();
}
try {
verify(chainCode);
System.out.println("Verify Success !!!");
} catch (Exception e) {
fail("Verify Fail !!");
}
}

@Test
public void testSign() {
byte[] test = "zhangsan".getBytes(StandardCharsets.UTF_8);
System.out.println(contractMF(test));
}
}

Loading…
Cancel
Save