@@ -0,0 +1,274 @@ | |||||
# 合约编译插件使用教程 | |||||
### 1、maven引入 | |||||
在pom.xml文件中引入合约编译插件: | |||||
```xml | |||||
<plugin> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>contract-maven-plugin</artifactId> | |||||
<version>1.0.0.RELEASE</version> | |||||
<executions> | |||||
<execution> | |||||
<id>make-contract</id> | |||||
<phase>package</phase> | |||||
<goals> | |||||
<goal>compile</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
<configuration> | |||||
<archive> | |||||
<manifest> | |||||
<mainClass>com.jd.chain.contracts.ContractTestInfImpl</mainClass> | |||||
</manifest> | |||||
</archive> | |||||
<finalName>contract</finalName> | |||||
</configuration> | |||||
</plugin> | |||||
``` | |||||
需要说明的几点如下: | |||||
+ 1)version:请根据实际JDChain发布版本确认,不同版本会有区别; | |||||
+ 2)executions->execution->id:该值请随意指定; | |||||
+ 3)executions->execution->phase:建议使用package及其后续阶段(若不了解phase含义,请自行查阅相关信息); | |||||
+ 4)executions->execution->goals->goal:必须使用compile; | |||||
+ 5)mainClass:必填,该类为需要发布的合约执行类(注意此处是类,不是接口),必须正确配置; | |||||
+ 6)finalName:必填,最终在编译正常的情况下,会产生{finalName}-jdchain-contract.jar文件,只有该文件是可以发布到JDChain的合约包; | |||||
### 2、执行命令 | |||||
使用mvn执行命令,下面两种方式均可: | |||||
方式一:只执行contract插件命令 | |||||
```shell | |||||
mvn clean compile contract:compile | |||||
``` | |||||
方式二:直接执行打包命令: | |||||
```shell | |||||
mvn clean package | |||||
``` | |||||
### 3、合约编写要求 | |||||
合约的执行结果会对整条链产生比较深刻的影响,为了使用户能够更好、更合理的使用合约,目前JDChain约定合约编写规则包括以下几点: | |||||
(违反其中任何一点都可能导致合约编译失败,但即使合约编译通过也不能保证合约可百分百运行正常) | |||||
+ 1)合约工程必须引入com.jd.blockchain:sdk-pack:该包中有合约正常编写需要使用的基本类; | |||||
+ 2)com.jd.blockchain:sdk-pack的scope必须定义为provided; | |||||
+ 3)合约发布必须通过合约编译插件进行打包:合约编译插件不但会对Jar包进行校验,同时也会加入JDChain独有的特征,只有具有该特征的Jar才能正常发布; | |||||
+ 4)合约中严禁使用随机数、IO、NIO等操作; | |||||
+ 5)合约打包时,请使用<scope>provided</scope>排除常用的工具包,例如FastJson、apache下的一些工具包等; | |||||
+ 6)合约必须有一个接口和该接口的实现类,详细要求如下: | |||||
- a. 接口必须有@Contract注解; | |||||
- b. 接口的可调用方法上必须有@ContractEvent注解,且每个注解中的name属性不能重复; | |||||
- c. 合约方法支持入参和返回值,其主要包括所有基本类型; | |||||
### 4、合约案例 | |||||
#### 4.1、代码实例 | |||||
以下是一个可创建银行账户,指定具体金额,并可以转账的合约代码(逻辑较简单,仅供参考): | |||||
合约接口代码如下: | |||||
```java | |||||
package com.jd.chain.contract; | |||||
@Contract | |||||
public interface TransferContract { | |||||
@ContractEvent(name = "create") | |||||
String create(String address, String account, long money); | |||||
@ContractEvent(name = "transfer") | |||||
String transfer(String address, String from, String to, long money); | |||||
@ContractEvent(name = "read") | |||||
long read(String address, String account); | |||||
@ContractEvent(name = "readAll") | |||||
String readAll(String address, String account); | |||||
} | |||||
``` | |||||
合约实现类代码如下: | |||||
```java | |||||
package com.jd.chain.contract; | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.ledger.KVDataEntry; | |||||
import com.jd.blockchain.ledger.KVDataVO; | |||||
import com.jd.blockchain.ledger.KVInfoVO; | |||||
public class TransferContractImpl implements EventProcessingAware, TransferContract { | |||||
private ContractEventContext eventContext; | |||||
private HashDigest ledgerHash; | |||||
@Override | |||||
public String create(String address, String account, long money) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
// 肯定有返回值,但若不存在则返回version=-1 | |||||
if (kvDataEntries != null && kvDataEntries.length > 0) { | |||||
long currVersion = kvDataEntries[0].getVersion(); | |||||
if (currVersion > -1) { | |||||
throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account)); | |||||
} | |||||
eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L); | |||||
} else { | |||||
throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58())); | |||||
} | |||||
return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n", | |||||
address, account, money); | |||||
} | |||||
@Override | |||||
public String transfer(String address, String from, String to, long money) { | |||||
// 首先查询余额 | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to); | |||||
if (kvDataEntries == null || kvDataEntries.length != 2) { | |||||
throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to)); | |||||
} else { | |||||
// 判断from账号中钱数量是否足够 | |||||
long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L; | |||||
for (KVDataEntry kvDataEntry : kvDataEntries) { | |||||
if (kvDataEntry.getKey().equals(from)) { | |||||
fromMoney = (long) kvDataEntry.getValue(); | |||||
fromVersion = kvDataEntry.getVersion(); | |||||
} else { | |||||
toMoney = (long) kvDataEntry.getValue(); | |||||
toVersion = kvDataEntry.getVersion(); | |||||
} | |||||
} | |||||
if (fromMoney < money) { | |||||
throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from)); | |||||
} | |||||
long fromNewMoney = fromMoney - money; | |||||
long toNewMoney = toMoney + money; | |||||
// 重新设置 | |||||
eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion); | |||||
eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion); | |||||
} | |||||
return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money); | |||||
} | |||||
@Override | |||||
public long read(String address, String account) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
return -1; | |||||
} | |||||
return (long)kvDataEntries[0].getValue(); | |||||
} | |||||
@Override | |||||
public String readAll(String address, String account) { | |||||
KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account); | |||||
// 获取最新的版本号 | |||||
if (kvDataEntries == null || kvDataEntries.length == 0) { | |||||
return ""; | |||||
} | |||||
long newestVersion = kvDataEntries[0].getVersion(); | |||||
if (newestVersion == -1) { | |||||
return ""; | |||||
} | |||||
KVDataVO[] kvDataVOS = new KVDataVO[1]; | |||||
long[] versions = new long[(int)newestVersion + 1]; | |||||
for (int i = 0; i < versions.length; i++) { | |||||
versions[i] = i; | |||||
} | |||||
KVDataVO kvDataVO = new KVDataVO(account, versions); | |||||
kvDataVOS[0] = kvDataVO; | |||||
KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS); | |||||
KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO); | |||||
return JSON.toJSONString(allEntries); | |||||
} | |||||
@Override | |||||
public void beforeEvent(ContractEventContext eventContext) { | |||||
this.eventContext = eventContext; | |||||
this.ledgerHash = eventContext.getCurrentLedgerHash(); | |||||
} | |||||
@Override | |||||
public void postEvent(ContractEventContext eventContext, Exception error) { | |||||
} | |||||
} | |||||
``` | |||||
#### 4.2、pom.xml文件实例 | |||||
```xml | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||||
<groupId>com.jd.chain</groupId> | |||||
<version>1.0.0.RELEASE</version> | |||||
<modelVersion>4.0.0</modelVersion> | |||||
<artifactId>contract-samples</artifactId> | |||||
<name>contract-samples</name> | |||||
<dependencies> | |||||
<dependency> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>sdk-pack</artifactId> | |||||
<version>1.0.0.RELEASE</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>com.alibaba</groupId> | |||||
<artifactId>fastjson</artifactId> | |||||
<version>1.2.32</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
</dependencies> | |||||
<build> | |||||
<plugins> | |||||
<plugin> | |||||
<groupId>com.jd.blockchain</groupId> | |||||
<artifactId>contract-maven-plugin</artifactId> | |||||
<version>1.0.0.RELEASE</version> | |||||
<executions> | |||||
<execution> | |||||
<id>make-contract</id> | |||||
<phase>package</phase> | |||||
<goals> | |||||
<goal>compile</goal> | |||||
</goals> | |||||
</execution> | |||||
</executions> | |||||
<configuration> | |||||
<archive> | |||||
<manifest> | |||||
<mainClass>com.jd.chain.contract.TransferContractImpl</mainClass> | |||||
</manifest> | |||||
</archive> | |||||
<finalName>contract</finalName> | |||||
</configuration> | |||||
</plugin> | |||||
</plugins> | |||||
</build> | |||||
</project> | |||||
``` |
@@ -10,10 +10,6 @@ | |||||
<artifactId>contract-maven-plugin</artifactId> | <artifactId>contract-maven-plugin</artifactId> | ||||
<packaging>maven-plugin</packaging> | <packaging>maven-plugin</packaging> | ||||
<properties> | |||||
<maven.version>3.3.9</maven.version> | |||||
</properties> | |||||
<dependencies> | <dependencies> | ||||
<dependency> | <dependency> | ||||
<groupId>com.jd.blockchain</groupId> | <groupId>com.jd.blockchain</groupId> | ||||
@@ -42,56 +38,24 @@ | |||||
<dependency> | <dependency> | ||||
<groupId>com.github.javaparser</groupId> | <groupId>com.github.javaparser</groupId> | ||||
<artifactId>javaparser-core</artifactId> | <artifactId>javaparser-core</artifactId> | ||||
<version>${javaparser.version}</version> | |||||
</dependency> | </dependency> | ||||
<!-- new --> | |||||
<dependency> | <dependency> | ||||
<groupId>org.apache.maven</groupId> | <groupId>org.apache.maven</groupId> | ||||
<artifactId>maven-plugin-api</artifactId> | <artifactId>maven-plugin-api</artifactId> | ||||
<version>3.3.9</version> | <version>3.3.9</version> | ||||
</dependency> | </dependency> | ||||
<dependency> | |||||
<groupId>org.apache.maven</groupId> | |||||
<artifactId>maven-core</artifactId> | |||||
<version>3.3.9</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.maven</groupId> | |||||
<artifactId>maven-artifact</artifactId> | |||||
<version>3.3.9</version> | |||||
<scope>provided</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.maven</groupId> | |||||
<artifactId>maven-compat</artifactId> | |||||
<version>3.3.9</version> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>junit</groupId> | |||||
<artifactId>junit</artifactId> | |||||
<version>4.12</version> | |||||
<scope>test</scope> | |||||
</dependency> | |||||
<dependency> | |||||
<groupId>org.apache.maven.plugin-testing</groupId> | |||||
<artifactId>maven-plugin-testing-harness</artifactId> | |||||
<scope>test</scope> | |||||
<version>3.3.0</version> | |||||
</dependency> | |||||
<!-- https://mvnrepository.com/artifact/org.apache.maven.plugin-tools/maven-plugin-annotations --> | |||||
<dependency> | <dependency> | ||||
<groupId>org.apache.maven.plugin-tools</groupId> | <groupId>org.apache.maven.plugin-tools</groupId> | ||||
<artifactId>maven-plugin-annotations</artifactId> | <artifactId>maven-plugin-annotations</artifactId> | ||||
<version>3.6.0</version> | <version>3.6.0</version> | ||||
<scope>provided</scope> | |||||
</dependency> | </dependency> | ||||
<dependency> | <dependency> | ||||
<groupId>org.apache.maven.shared</groupId> | |||||
<artifactId>maven-invoker</artifactId> | |||||
<version>3.0.1</version> | |||||
<groupId>org.apache.maven.plugins</groupId> | |||||
<artifactId>maven-assembly-plugin</artifactId> | |||||
<version>2.6</version> | |||||
</dependency> | </dependency> | ||||
</dependencies> | </dependencies> | ||||
@@ -103,27 +67,6 @@ | |||||
<artifactId>maven-plugin-plugin</artifactId> | <artifactId>maven-plugin-plugin</artifactId> | ||||
<version>3.5</version> | <version>3.5</version> | ||||
</plugin> | </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> | |||||
</plugins> | |||||
</build> | </build> | ||||
</project> | </project> |
@@ -1,216 +1,216 @@ | |||||
package com.jd.blockchain.contract.maven; | |||||
import org.apache.commons.io.FileUtils; | |||||
import org.apache.maven.model.Model; | |||||
import org.apache.maven.model.Plugin; | |||||
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; | |||||
import org.apache.maven.shared.invoker.*; | |||||
import org.codehaus.plexus.util.xml.Xpp3Dom; | |||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.ByteArrayOutputStream; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
@Mojo(name = "contractCheck") | |||||
public class ContractCheckMojo extends AbstractMojo { | |||||
Logger LOG = LoggerFactory.getLogger(ContractCheckMojo.class); | |||||
public static final String CONTRACT_VERIFY = "contractVerify"; | |||||
private static final String CONTRACT_MAVEN_PLUGIN = "contract-maven-plugin"; | |||||
private static final String MAVEN_ASSEMBLY_PLUGIN = "maven-assembly-plugin"; | |||||
private static final String JDCHAIN_PACKAGE = "com.jd.blockchain"; | |||||
private static final String APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins"; | |||||
private static final String GOALS_VERIFY = "package"; | |||||
private static final String GOALS_PACKAGE = "package"; | |||||
private static final String OUT_POM_XML = "ContractPom.xml"; | |||||
@Parameter(defaultValue = "${project}", required = true, readonly = true) | |||||
private MavenProject project; | |||||
/** | |||||
* jar's name; | |||||
*/ | |||||
@Parameter | |||||
private String finalName; | |||||
/** | |||||
* mainClass; | |||||
*/ | |||||
@Parameter | |||||
private String mainClass; | |||||
/** | |||||
* ledgerVersion; | |||||
*/ | |||||
@Parameter | |||||
private String ledgerVersion; | |||||
/** | |||||
* mvnHome; | |||||
*/ | |||||
@Parameter | |||||
private String mvnHome; | |||||
/** | |||||
* first compile the class, then parse it; | |||||
*/ | |||||
@Override | |||||
public void execute() throws MojoFailureException { | |||||
compileFiles(); | |||||
} | |||||
private void compileFiles() throws MojoFailureException { | |||||
try (FileInputStream fis = new FileInputStream(project.getFile())) { | |||||
MavenXpp3Reader reader = new MavenXpp3Reader(); | |||||
Model model = reader.read(fis); | |||||
//delete this plugin(contractCheck) from destination pom.xml;then add the proper plugins; | |||||
Plugin plugin = model.getBuild().getPluginsAsMap() | |||||
.get(JDCHAIN_PACKAGE + ":" + CONTRACT_MAVEN_PLUGIN); | |||||
if(plugin == null){ | |||||
plugin = model.getBuild().getPluginsAsMap() | |||||
.get(APACHE_MAVEN_PLUGINS + ":" + CONTRACT_MAVEN_PLUGIN); | |||||
} | |||||
if(plugin == null) { | |||||
return; | |||||
} | |||||
model.getBuild().removePlugin(plugin); | |||||
List<Plugin> plugins = new ArrayList<>(); | |||||
plugins.add(createAssembly()); | |||||
plugins.add(createContractVerify()); | |||||
model.getBuild().setPlugins(plugins); | |||||
handle(model); | |||||
} catch (Exception e) { | |||||
LOG.error(e.getMessage()); | |||||
throw new MojoFailureException(e.getMessage()); | |||||
} | |||||
} | |||||
private void invokeCompile(File file) { | |||||
InvocationRequest request = new DefaultInvocationRequest(); | |||||
Invoker invoker = new DefaultInvoker(); | |||||
try { | |||||
request.setPomFile(file); | |||||
request.setGoals(Collections.singletonList(GOALS_VERIFY)); | |||||
invoker.setMavenHome(new File(mvnHome)); | |||||
invoker.execute(request); | |||||
} catch (MavenInvocationException e) { | |||||
LOG.error(e.getMessage()); | |||||
throw new IllegalStateException(e); | |||||
} | |||||
} | |||||
private Plugin createContractVerify() { | |||||
Plugin plugin = new Plugin(); | |||||
plugin.setGroupId(JDCHAIN_PACKAGE); | |||||
plugin.setArtifactId(CONTRACT_MAVEN_PLUGIN); | |||||
plugin.setVersion(ledgerVersion); | |||||
Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); | |||||
finalNameNode.setValue(finalName); | |||||
Xpp3Dom configuration = new Xpp3Dom("configuration"); | |||||
configuration.addChild(finalNameNode); | |||||
plugin.setConfiguration(configuration); | |||||
plugin.setExecutions(pluginExecution("make-assembly", GOALS_VERIFY, CONTRACT_VERIFY)); | |||||
return plugin; | |||||
} | |||||
private Plugin createAssembly() { | |||||
Plugin plugin = new Plugin(); | |||||
plugin.setArtifactId(MAVEN_ASSEMBLY_PLUGIN); | |||||
Xpp3Dom configuration = new Xpp3Dom("configuration"); | |||||
Xpp3Dom mainClassNode = new Xpp3Dom("mainClass"); | |||||
mainClassNode.setValue(mainClass); | |||||
Xpp3Dom manifest = new Xpp3Dom("manifest"); | |||||
manifest.addChild(mainClassNode); | |||||
Xpp3Dom archive = new Xpp3Dom("archive"); | |||||
archive.addChild(manifest); | |||||
Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); | |||||
finalNameNode.setValue(finalName); | |||||
Xpp3Dom appendAssemblyId = new Xpp3Dom("appendAssemblyId"); | |||||
appendAssemblyId.setValue("false"); | |||||
Xpp3Dom descriptorRef = new Xpp3Dom("descriptorRef"); | |||||
descriptorRef.setValue("jar-with-dependencies"); | |||||
Xpp3Dom descriptorRefs = new Xpp3Dom("descriptorRefs"); | |||||
descriptorRefs.addChild(descriptorRef); | |||||
configuration.addChild(finalNameNode); | |||||
configuration.addChild(appendAssemblyId); | |||||
configuration.addChild(archive); | |||||
configuration.addChild(descriptorRefs); | |||||
plugin.setConfiguration(configuration); | |||||
plugin.setExecutions(pluginExecution("make-assembly", GOALS_PACKAGE, "single")); | |||||
return plugin; | |||||
} | |||||
private List<PluginExecution> pluginExecution(String id, String phase, String goal) { | |||||
PluginExecution pluginExecution = new PluginExecution(); | |||||
pluginExecution.setId(id); | |||||
pluginExecution.setPhase(phase); | |||||
List<String> goals = new ArrayList<>(); | |||||
goals.add(goal); | |||||
pluginExecution.setGoals(goals); | |||||
List<PluginExecution> pluginExecutions = new ArrayList<>(); | |||||
pluginExecutions.add(pluginExecution); | |||||
return pluginExecutions; | |||||
} | |||||
private void handle(Model model) throws IOException { | |||||
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer(); | |||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |||||
mavenXpp3Writer.write(outputStream, model); | |||||
byte[] buffer = outputStream.toByteArray(); | |||||
File outPom = new File(project.getBasedir().getPath(), OUT_POM_XML); | |||||
FileUtils.writeByteArrayToFile(outPom, buffer); | |||||
invokeCompile(outPom); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.contract.maven; | |||||
// | |||||
//import org.apache.commons.io.FileUtils; | |||||
//import org.apache.maven.model.Model; | |||||
//import org.apache.maven.model.Plugin; | |||||
//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; | |||||
//import org.apache.maven.shared.invoker.*; | |||||
//import org.codehaus.plexus.util.xml.Xpp3Dom; | |||||
//import org.slf4j.Logger; | |||||
//import org.slf4j.LoggerFactory; | |||||
// | |||||
//import java.io.ByteArrayOutputStream; | |||||
//import java.io.File; | |||||
//import java.io.FileInputStream; | |||||
//import java.io.IOException; | |||||
//import java.util.ArrayList; | |||||
//import java.util.Collections; | |||||
//import java.util.List; | |||||
// | |||||
// | |||||
//@Mojo(name = "contractCheck") | |||||
//public class ContractCheckMojo extends AbstractMojo { | |||||
// | |||||
// Logger LOG = LoggerFactory.getLogger(ContractCheckMojo.class); | |||||
// | |||||
// public static final String CONTRACT_VERIFY = "contractVerify"; | |||||
// | |||||
// private static final String CONTRACT_MAVEN_PLUGIN = "contract-maven-plugin"; | |||||
// | |||||
// private static final String MAVEN_ASSEMBLY_PLUGIN = "maven-assembly-plugin"; | |||||
// | |||||
// private static final String JDCHAIN_PACKAGE = "com.jd.blockchain"; | |||||
// | |||||
// private static final String APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins"; | |||||
// | |||||
// private static final String GOALS_VERIFY = "package"; | |||||
// | |||||
// private static final String GOALS_PACKAGE = "package"; | |||||
// | |||||
// private static final String OUT_POM_XML = "ContractPom.xml"; | |||||
// | |||||
// @Parameter(defaultValue = "${project}", required = true, readonly = true) | |||||
// private MavenProject project; | |||||
// | |||||
// /** | |||||
// * jar's name; | |||||
// */ | |||||
// @Parameter | |||||
// private String finalName; | |||||
// | |||||
// /** | |||||
// * mainClass; | |||||
// */ | |||||
// @Parameter | |||||
// private String mainClass; | |||||
// /** | |||||
// * ledgerVersion; | |||||
// */ | |||||
// @Parameter | |||||
// private String ledgerVersion; | |||||
// | |||||
// /** | |||||
// * mvnHome; | |||||
// */ | |||||
// @Parameter | |||||
// private String mvnHome; | |||||
// | |||||
// /** | |||||
// * first compile the class, then parse it; | |||||
// */ | |||||
// @Override | |||||
// public void execute() throws MojoFailureException { | |||||
// compileFiles(); | |||||
// } | |||||
// | |||||
// private void compileFiles() throws MojoFailureException { | |||||
// try (FileInputStream fis = new FileInputStream(project.getFile())) { | |||||
// | |||||
// MavenXpp3Reader reader = new MavenXpp3Reader(); | |||||
// Model model = reader.read(fis); | |||||
// | |||||
// //delete this plugin(contractCheck) from destination pom.xml;then add the proper plugins; | |||||
// Plugin plugin = model.getBuild().getPluginsAsMap() | |||||
// .get(JDCHAIN_PACKAGE + ":" + CONTRACT_MAVEN_PLUGIN); | |||||
// if(plugin == null){ | |||||
// plugin = model.getBuild().getPluginsAsMap() | |||||
// .get(APACHE_MAVEN_PLUGINS + ":" + CONTRACT_MAVEN_PLUGIN); | |||||
// } | |||||
// | |||||
// if(plugin == null) { | |||||
// return; | |||||
// } | |||||
// | |||||
// model.getBuild().removePlugin(plugin); | |||||
// | |||||
// List<Plugin> plugins = new ArrayList<>(); | |||||
// plugins.add(createAssembly()); | |||||
// plugins.add(createContractVerify()); | |||||
// | |||||
// model.getBuild().setPlugins(plugins); | |||||
// | |||||
// handle(model); | |||||
// | |||||
// } catch (Exception e) { | |||||
// LOG.error(e.getMessage()); | |||||
// throw new MojoFailureException(e.getMessage()); | |||||
// } | |||||
// } | |||||
// | |||||
// private void invokeCompile(File file) { | |||||
// InvocationRequest request = new DefaultInvocationRequest(); | |||||
// | |||||
// Invoker invoker = new DefaultInvoker(); | |||||
// try { | |||||
// request.setPomFile(file); | |||||
// | |||||
// request.setGoals(Collections.singletonList(GOALS_VERIFY)); | |||||
// invoker.setMavenHome(new File(mvnHome)); | |||||
// invoker.execute(request); | |||||
// } catch (MavenInvocationException e) { | |||||
// LOG.error(e.getMessage()); | |||||
// throw new IllegalStateException(e); | |||||
// } | |||||
// } | |||||
// | |||||
// private Plugin createContractVerify() { | |||||
// Plugin plugin = new Plugin(); | |||||
// plugin.setGroupId(JDCHAIN_PACKAGE); | |||||
// plugin.setArtifactId(CONTRACT_MAVEN_PLUGIN); | |||||
// plugin.setVersion(ledgerVersion); | |||||
// | |||||
// Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); | |||||
// finalNameNode.setValue(finalName); | |||||
// Xpp3Dom configuration = new Xpp3Dom("configuration"); | |||||
// configuration.addChild(finalNameNode); | |||||
// | |||||
// plugin.setConfiguration(configuration); | |||||
// plugin.setExecutions(pluginExecution("make-assembly", GOALS_VERIFY, CONTRACT_VERIFY)); | |||||
// | |||||
// return plugin; | |||||
// } | |||||
// | |||||
// private Plugin createAssembly() { | |||||
// Plugin plugin = new Plugin(); | |||||
// plugin.setArtifactId(MAVEN_ASSEMBLY_PLUGIN); | |||||
// | |||||
// Xpp3Dom configuration = new Xpp3Dom("configuration"); | |||||
// | |||||
// Xpp3Dom mainClassNode = new Xpp3Dom("mainClass"); | |||||
// mainClassNode.setValue(mainClass); | |||||
// | |||||
// Xpp3Dom manifest = new Xpp3Dom("manifest"); | |||||
// manifest.addChild(mainClassNode); | |||||
// | |||||
// Xpp3Dom archive = new Xpp3Dom("archive"); | |||||
// archive.addChild(manifest); | |||||
// | |||||
// Xpp3Dom finalNameNode = new Xpp3Dom("finalName"); | |||||
// finalNameNode.setValue(finalName); | |||||
// | |||||
// Xpp3Dom appendAssemblyId = new Xpp3Dom("appendAssemblyId"); | |||||
// appendAssemblyId.setValue("false"); | |||||
// | |||||
// Xpp3Dom descriptorRef = new Xpp3Dom("descriptorRef"); | |||||
// descriptorRef.setValue("jar-with-dependencies"); | |||||
// Xpp3Dom descriptorRefs = new Xpp3Dom("descriptorRefs"); | |||||
// descriptorRefs.addChild(descriptorRef); | |||||
// | |||||
// configuration.addChild(finalNameNode); | |||||
// configuration.addChild(appendAssemblyId); | |||||
// configuration.addChild(archive); | |||||
// configuration.addChild(descriptorRefs); | |||||
// | |||||
// plugin.setConfiguration(configuration); | |||||
// plugin.setExecutions(pluginExecution("make-assembly", GOALS_PACKAGE, "single")); | |||||
// | |||||
// return plugin; | |||||
// } | |||||
// | |||||
// private List<PluginExecution> pluginExecution(String id, String phase, String goal) { | |||||
// PluginExecution pluginExecution = new PluginExecution(); | |||||
// pluginExecution.setId(id); | |||||
// pluginExecution.setPhase(phase); | |||||
// List<String> goals = new ArrayList<>(); | |||||
// goals.add(goal); | |||||
// pluginExecution.setGoals(goals); | |||||
// List<PluginExecution> pluginExecutions = new ArrayList<>(); | |||||
// pluginExecutions.add(pluginExecution); | |||||
// | |||||
// return pluginExecutions; | |||||
// } | |||||
// | |||||
// private void handle(Model model) throws IOException { | |||||
// | |||||
// MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer(); | |||||
// | |||||
// ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | |||||
// | |||||
// mavenXpp3Writer.write(outputStream, model); | |||||
// | |||||
// byte[] buffer = outputStream.toByteArray(); | |||||
// | |||||
// File outPom = new File(project.getBasedir().getPath(), OUT_POM_XML); | |||||
// | |||||
// FileUtils.writeByteArrayToFile(outPom, buffer); | |||||
// | |||||
// invokeCompile(outPom); | |||||
// } | |||||
//} |
@@ -0,0 +1,30 @@ | |||||
package com.jd.blockchain.contract.maven; | |||||
import org.apache.maven.plugin.MojoExecutionException; | |||||
import org.apache.maven.plugin.MojoFailureException; | |||||
import org.apache.maven.plugin.assembly.mojos.SingleAssemblyMojo; | |||||
import org.apache.maven.plugins.annotations.Mojo; | |||||
@Mojo(name = "compile") | |||||
public class ContractCompileMojo extends SingleAssemblyMojo { | |||||
public static final String JAR_DEPENDENCE = "jar-with-dependencies"; | |||||
@Override | |||||
public void execute() throws MojoExecutionException, MojoFailureException { | |||||
// 要求必须有MainClass | |||||
try { | |||||
String mainClass = super.getJarArchiveConfiguration().getManifest().getMainClass(); | |||||
super.getLog().debug("MainClass is " + mainClass); | |||||
} catch (Exception e) { | |||||
throw new MojoFailureException("MainClass is null: " + e.getMessage(), e ); | |||||
} | |||||
super.setDescriptorRefs(new String[]{JAR_DEPENDENCE}); | |||||
super.execute(); | |||||
ContractResolveEngine engine = new ContractResolveEngine(getLog(), getProject(), getFinalName()); | |||||
engine.compileAndVerify(); | |||||
} | |||||
} |
@@ -1,176 +1,176 @@ | |||||
package com.jd.blockchain.contract.maven; | |||||
import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.*; | |||||
import com.jd.blockchain.sdk.BlockchainService; | |||||
import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.utils.Bytes; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.net.NetworkAddress; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
/** | |||||
* @Author zhaogw | |||||
* @Date 2018/11/2 10:18 | |||||
*/ | |||||
public enum ContractDeployExeUtil { | |||||
instance; | |||||
private BlockchainService bcsrv; | |||||
private Bytes contractAddress; | |||||
public BlockchainKeypair getKeyPair(String pubPath, String prvPath, String rawPassword){ | |||||
PubKey pub = null; | |||||
PrivKey prv = null; | |||||
try { | |||||
prv = KeyGenCommand.readPrivKey(prvPath, KeyGenCommand.encodePassword(rawPassword)); | |||||
pub = KeyGenCommand.readPubKey(pubPath); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return new BlockchainKeypair(pub, prv); | |||||
} | |||||
public PubKey getPubKey(String pubPath){ | |||||
PubKey pub = null; | |||||
try { | |||||
if(pubPath == null){ | |||||
BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | |||||
pub = contractKeyPair.getPubKey(); | |||||
}else { | |||||
pub = KeyGenCommand.readPubKey(pubPath); | |||||
} | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
} | |||||
return pub; | |||||
} | |||||
public byte[] getChainCode(String path){ | |||||
byte[] chainCode = null; | |||||
File file = null; | |||||
InputStream input = null; | |||||
try { | |||||
file = new File(path); | |||||
input = new FileInputStream(file); | |||||
chainCode = new byte[input.available()]; | |||||
input.read(chainCode); | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} finally { | |||||
try { | |||||
if(input!=null){ | |||||
input.close(); | |||||
} | |||||
} catch (IOException e) { | |||||
e.printStackTrace(); | |||||
} | |||||
} | |||||
return chainCode; | |||||
} | |||||
private void register(){ | |||||
DataContractRegistry.register(TransactionContent.class); | |||||
DataContractRegistry.register(TransactionContentBody.class); | |||||
DataContractRegistry.register(TransactionRequest.class); | |||||
DataContractRegistry.register(NodeRequest.class); | |||||
DataContractRegistry.register(EndpointRequest.class); | |||||
DataContractRegistry.register(TransactionResponse.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.class); | |||||
DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); | |||||
DataContractRegistry.register(Operation.class); | |||||
DataContractRegistry.register(ContractCodeDeployOperation.class); | |||||
DataContractRegistry.register(ContractEventSendOperation.class); | |||||
DataContractRegistry.register(DataAccountRegisterOperation.class); | |||||
DataContractRegistry.register(UserRegisterOperation.class); | |||||
} | |||||
public BlockchainService initBcsrv(String host, int port) { | |||||
if(bcsrv!=null){ | |||||
return bcsrv; | |||||
} | |||||
NetworkAddress addr = new NetworkAddress(host, port); | |||||
GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(addr); | |||||
bcsrv = gwsrvFact.getBlockchainService(); | |||||
return bcsrv; | |||||
} | |||||
public boolean deploy(HashDigest ledgerHash, BlockchainIdentity contractIdentity, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
register(); | |||||
TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
txTpl.contracts().deploy(contractIdentity, chainCode); | |||||
PreparedTransaction ptx = txTpl.prepare(); | |||||
ptx.sign(ownerKey); | |||||
// 提交并等待共识返回; | |||||
TransactionResponse txResp = ptx.commit(); | |||||
// 验证结果; | |||||
contractAddress = contractIdentity.getAddress(); | |||||
this.setContractAddress(contractAddress); | |||||
System.out.println("contract's address="+contractAddress); | |||||
return txResp.isSuccess(); | |||||
} | |||||
public boolean deploy(String host, int port, HashDigest ledgerHash, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
register(); | |||||
BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity(); | |||||
initBcsrv(host,port); | |||||
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
} | |||||
// 根据用户指定的公钥生成合约地址 | |||||
public boolean deploy(String host, int port, String ledger,String ownerPubPath, String ownerPrvPath, | |||||
String ownerPassword, String chainCodePath,String pubPath){ | |||||
PubKey pubKey = getPubKey(pubPath); | |||||
BlockchainIdentity contractIdentity = new BlockchainIdentityData(pubKey); | |||||
byte[] chainCode = getChainCode(chainCodePath); | |||||
BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
initBcsrv(host,port); | |||||
return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
} | |||||
// 暂不支持从插件执行合约;此外,由于合约参数调用的格式发生变化,故此方法被废弃;by: huanghaiquan at 2019-04-30; | |||||
// public boolean exeContract(String ledger,String ownerPubPath, String ownerPrvPath, | |||||
// String ownerPassword,String event,String contractArgs){ | |||||
// BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
//package com.jd.blockchain.contract.maven; | |||||
// | // | ||||
// // 定义交易,传输最简单的数字、字符串、提取合约中的地址; | |||||
// TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
// txTpl.contractEvents().send(getContractAddress(),event,contractArgs.getBytes()); | |||||
//import com.jd.blockchain.binaryproto.DataContractRegistry; | |||||
//import com.jd.blockchain.crypto.HashDigest; | |||||
//import com.jd.blockchain.crypto.PrivKey; | |||||
//import com.jd.blockchain.crypto.PubKey; | |||||
//import com.jd.blockchain.ledger.*; | |||||
//import com.jd.blockchain.sdk.BlockchainService; | |||||
//import com.jd.blockchain.sdk.client.GatewayServiceFactory; | |||||
//import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
//import com.jd.blockchain.utils.Bytes; | |||||
//import com.jd.blockchain.utils.codec.Base58Utils; | |||||
//import com.jd.blockchain.utils.net.NetworkAddress; | |||||
// | |||||
//import java.io.File; | |||||
//import java.io.FileInputStream; | |||||
//import java.io.IOException; | |||||
//import java.io.InputStream; | |||||
// | |||||
///** | |||||
// * @Author zhaogw | |||||
// * @Date 2018/11/2 10:18 | |||||
// */ | |||||
//public enum ContractDeployExeUtil { | |||||
// instance; | |||||
// private BlockchainService bcsrv; | |||||
// private Bytes contractAddress; | |||||
// | |||||
// public BlockchainKeypair getKeyPair(String pubPath, String prvPath, String rawPassword){ | |||||
// PubKey pub = null; | |||||
// PrivKey prv = null; | |||||
// try { | |||||
// prv = KeyGenCommand.readPrivKey(prvPath, KeyGenCommand.encodePassword(rawPassword)); | |||||
// pub = KeyGenCommand.readPubKey(pubPath); | |||||
// | |||||
// } catch (Exception e) { | |||||
// e.printStackTrace(); | |||||
// } | |||||
// | |||||
// return new BlockchainKeypair(pub, prv); | |||||
// } | |||||
// | |||||
// public PubKey getPubKey(String pubPath){ | |||||
// PubKey pub = null; | |||||
// try { | |||||
// if(pubPath == null){ | |||||
// BlockchainKeypair contractKeyPair = BlockchainKeyGenerator.getInstance().generate(); | |||||
// pub = contractKeyPair.getPubKey(); | |||||
// }else { | |||||
// pub = KeyGenCommand.readPubKey(pubPath); | |||||
// } | |||||
// | |||||
// } catch (Exception e) { | |||||
// e.printStackTrace(); | |||||
// } | |||||
// | |||||
// return pub; | |||||
// } | |||||
// public byte[] getChainCode(String path){ | |||||
// byte[] chainCode = null; | |||||
// File file = null; | |||||
// InputStream input = null; | |||||
// try { | |||||
// file = new File(path); | |||||
// input = new FileInputStream(file); | |||||
// chainCode = new byte[input.available()]; | |||||
// input.read(chainCode); | |||||
// | |||||
// } catch (IOException e) { | |||||
// e.printStackTrace(); | |||||
// } finally { | |||||
// try { | |||||
// if(input!=null){ | |||||
// input.close(); | |||||
// } | |||||
// } catch (IOException e) { | |||||
// e.printStackTrace(); | |||||
// } | |||||
// } | |||||
// return chainCode; | |||||
// } | |||||
// | |||||
// private void register(){ | |||||
// DataContractRegistry.register(TransactionContent.class); | |||||
// DataContractRegistry.register(TransactionContentBody.class); | |||||
// DataContractRegistry.register(TransactionRequest.class); | |||||
// DataContractRegistry.register(NodeRequest.class); | |||||
// DataContractRegistry.register(EndpointRequest.class); | |||||
// DataContractRegistry.register(TransactionResponse.class); | |||||
// DataContractRegistry.register(DataAccountKVSetOperation.class); | |||||
// DataContractRegistry.register(DataAccountKVSetOperation.KVWriteEntry.class); | |||||
// DataContractRegistry.register(Operation.class); | |||||
// DataContractRegistry.register(ContractCodeDeployOperation.class); | |||||
// DataContractRegistry.register(ContractEventSendOperation.class); | |||||
// DataContractRegistry.register(DataAccountRegisterOperation.class); | |||||
// DataContractRegistry.register(UserRegisterOperation.class); | |||||
// } | |||||
// | |||||
// public BlockchainService initBcsrv(String host, int port) { | |||||
// if(bcsrv!=null){ | |||||
// return bcsrv; | |||||
// } | |||||
// NetworkAddress addr = new NetworkAddress(host, port); | |||||
// GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(addr); | |||||
// bcsrv = gwsrvFact.getBlockchainService(); | |||||
// return bcsrv; | |||||
// } | |||||
// | |||||
// public boolean deploy(HashDigest ledgerHash, BlockchainIdentity contractIdentity, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
// register(); | |||||
// | // | ||||
// // 签名; | |||||
// TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
// txTpl.contracts().deploy(contractIdentity, chainCode); | |||||
// PreparedTransaction ptx = txTpl.prepare(); | // PreparedTransaction ptx = txTpl.prepare(); | ||||
// ptx.sign(ownerKey); | // ptx.sign(ownerKey); | ||||
// | |||||
// // 提交并等待共识返回; | // // 提交并等待共识返回; | ||||
// TransactionResponse txResp = ptx.commit(); | // TransactionResponse txResp = ptx.commit(); | ||||
// | // | ||||
// // 验证结果; | // // 验证结果; | ||||
// contractAddress = contractIdentity.getAddress(); | |||||
// this.setContractAddress(contractAddress); | |||||
// System.out.println("contract's address="+contractAddress); | |||||
// return txResp.isSuccess(); | // return txResp.isSuccess(); | ||||
// } | // } | ||||
public Bytes getContractAddress() { | |||||
return contractAddress; | |||||
} | |||||
public void setContractAddress(Bytes contractAddress) { | |||||
this.contractAddress = contractAddress; | |||||
} | |||||
} | |||||
// public boolean deploy(String host, int port, HashDigest ledgerHash, BlockchainKeypair ownerKey, byte[] chainCode){ | |||||
// register(); | |||||
// | |||||
// BlockchainIdentity contractIdentity = BlockchainKeyGenerator.getInstance().generate().getIdentity(); | |||||
// initBcsrv(host,port); | |||||
// return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
// } | |||||
// | |||||
// // 根据用户指定的公钥生成合约地址 | |||||
// public boolean deploy(String host, int port, String ledger,String ownerPubPath, String ownerPrvPath, | |||||
// String ownerPassword, String chainCodePath,String pubPath){ | |||||
// PubKey pubKey = getPubKey(pubPath); | |||||
// BlockchainIdentity contractIdentity = new BlockchainIdentityData(pubKey); | |||||
// byte[] chainCode = getChainCode(chainCodePath); | |||||
// | |||||
// BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
// initBcsrv(host,port); | |||||
// return deploy(ledgerHash, contractIdentity, ownerKey, chainCode); | |||||
// } | |||||
// | |||||
// | |||||
//// 暂不支持从插件执行合约;此外,由于合约参数调用的格式发生变化,故此方法被废弃;by: huanghaiquan at 2019-04-30; | |||||
// | |||||
//// public boolean exeContract(String ledger,String ownerPubPath, String ownerPrvPath, | |||||
//// String ownerPassword,String event,String contractArgs){ | |||||
//// BlockchainKeypair ownerKey = getKeyPair(ownerPubPath, ownerPrvPath, ownerPassword); | |||||
//// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
//// | |||||
//// // 定义交易,传输最简单的数字、字符串、提取合约中的地址; | |||||
//// TransactionTemplate txTpl = bcsrv.newTransaction(ledgerHash); | |||||
//// txTpl.contractEvents().send(getContractAddress(),event,contractArgs.getBytes()); | |||||
//// | |||||
//// // 签名; | |||||
//// PreparedTransaction ptx = txTpl.prepare(); | |||||
//// ptx.sign(ownerKey); | |||||
//// | |||||
//// // 提交并等待共识返回; | |||||
//// TransactionResponse txResp = ptx.commit(); | |||||
//// | |||||
//// // 验证结果; | |||||
//// return txResp.isSuccess(); | |||||
//// } | |||||
// | |||||
// public Bytes getContractAddress() { | |||||
// return contractAddress; | |||||
// } | |||||
// | |||||
// public void setContractAddress(Bytes contractAddress) { | |||||
// this.contractAddress = contractAddress; | |||||
// } | |||||
//} |
@@ -1,119 +1,120 @@ | |||||
package com.jd.blockchain.contract.maven; | |||||
import com.jd.blockchain.crypto.HashDigest; | |||||
import com.jd.blockchain.crypto.PrivKey; | |||||
import com.jd.blockchain.crypto.PubKey; | |||||
import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
import com.jd.blockchain.utils.StringUtils; | |||||
import com.jd.blockchain.utils.codec.Base58Utils; | |||||
import com.jd.blockchain.utils.io.FileUtils; | |||||
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.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.File; | |||||
import java.io.FileInputStream; | |||||
import java.io.IOException; | |||||
import java.io.InputStream; | |||||
import java.util.Properties; | |||||
/** | |||||
* for contract remote deploy; | |||||
* @goal contractDeploy | |||||
* @phase process-sources | |||||
* @Author zhaogw | |||||
* @Date 2018/10/18 10:12 | |||||
*/ | |||||
@Mojo(name = "deploy") | |||||
public class ContractDeployMojo extends AbstractMojo { | |||||
Logger logger = LoggerFactory.getLogger(ContractDeployMojo.class); | |||||
@Parameter | |||||
private File config; | |||||
@Override | |||||
public void execute()throws MojoFailureException { | |||||
Properties prop = new Properties(); | |||||
InputStream input = null; | |||||
try { | |||||
input = new FileInputStream(config); | |||||
prop.load(input); | |||||
} catch (IOException ex) { | |||||
logger.error(ex.getMessage()); | |||||
throw new MojoFailureException("io error"); | |||||
} finally { | |||||
if (input != null) { | |||||
try { | |||||
input.close(); | |||||
} catch (IOException e) { | |||||
logger.error(e.getMessage()); | |||||
} | |||||
} | |||||
} | |||||
int port; | |||||
try { | |||||
port = Integer.parseInt(prop.getProperty("port")); | |||||
}catch (NumberFormatException e){ | |||||
logger.error(e.getMessage()); | |||||
throw new MojoFailureException("invalid port"); | |||||
} | |||||
String host = prop.getProperty("host"); | |||||
String ledger = prop.getProperty("ledger"); | |||||
String pubKey = prop.getProperty("pubKey"); | |||||
String prvKey = prop.getProperty("prvKey"); | |||||
String password = prop.getProperty("password"); | |||||
String contractPath = prop.getProperty("contractPath"); | |||||
if(StringUtils.isEmpty(host)){ | |||||
logger.info("host不能为空"); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(ledger)){ | |||||
logger.info("ledger不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(pubKey)){ | |||||
logger.info("pubKey不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(prvKey)){ | |||||
logger.info("prvKey不能为空."); | |||||
return; | |||||
} | |||||
if(StringUtils.isEmpty(contractPath)){ | |||||
logger.info("contractPath不能为空."); | |||||
return; | |||||
} | |||||
File contract = new File(contractPath); | |||||
if (!contract.isFile()){ | |||||
logger.info("文件"+contractPath+"不存在"); | |||||
return; | |||||
} | |||||
byte[] contractBytes = FileUtils.readBytes(contractPath); | |||||
PrivKey prv = KeyGenCommand.decodePrivKeyWithRawPassword(prvKey, password); | |||||
PubKey pub = KeyGenCommand.decodePubKey(pubKey); | |||||
BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv); | |||||
HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
StringBuffer sb = new StringBuffer(); | |||||
sb.append("host:"+ host).append(",port:"+port).append(",ledgerHash:"+ledgerHash.toBase58()). | |||||
append(",pubKey:"+pubKey).append(",prvKey:"+prv).append(",contractPath:"+contractPath); | |||||
logger.info(sb.toString()); | |||||
ContractDeployExeUtil.instance.deploy(host,port,ledgerHash, blockchainKeyPair, contractBytes); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.contract.maven; | |||||
// | |||||
//import com.jd.blockchain.crypto.HashDigest; | |||||
//import com.jd.blockchain.crypto.PrivKey; | |||||
//import com.jd.blockchain.crypto.PubKey; | |||||
//import com.jd.blockchain.ledger.BlockchainKeypair; | |||||
//import com.jd.blockchain.tools.keygen.KeyGenCommand; | |||||
//import com.jd.blockchain.utils.StringUtils; | |||||
//import com.jd.blockchain.utils.codec.Base58Utils; | |||||
//import com.jd.blockchain.utils.io.FileUtils; | |||||
//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.slf4j.Logger; | |||||
//import org.slf4j.LoggerFactory; | |||||
// | |||||
//import java.io.File; | |||||
//import java.io.FileInputStream; | |||||
//import java.io.IOException; | |||||
//import java.io.InputStream; | |||||
//import java.util.Properties; | |||||
// | |||||
///** | |||||
// * for contract remote deploy; | |||||
// * @goal contractDeploy | |||||
// * @phase process-sources | |||||
// * @Author zhaogw | |||||
// * @Date 2018/10/18 10:12 | |||||
// */ | |||||
// | |||||
//@Mojo(name = "deploy") | |||||
//public class ContractDeployMojo extends AbstractMojo { | |||||
// Logger logger = LoggerFactory.getLogger(ContractDeployMojo.class); | |||||
// | |||||
// @Parameter | |||||
// private File config; | |||||
// | |||||
// @Override | |||||
// public void execute()throws MojoFailureException { | |||||
// | |||||
// Properties prop = new Properties(); | |||||
// InputStream input = null; | |||||
// | |||||
// try { | |||||
// input = new FileInputStream(config); | |||||
// prop.load(input); | |||||
// | |||||
// } catch (IOException ex) { | |||||
// logger.error(ex.getMessage()); | |||||
// throw new MojoFailureException("io error"); | |||||
// } finally { | |||||
// if (input != null) { | |||||
// try { | |||||
// input.close(); | |||||
// } catch (IOException e) { | |||||
// logger.error(e.getMessage()); | |||||
// } | |||||
// } | |||||
// } | |||||
// int port; | |||||
// try { | |||||
// port = Integer.parseInt(prop.getProperty("port")); | |||||
// }catch (NumberFormatException e){ | |||||
// logger.error(e.getMessage()); | |||||
// throw new MojoFailureException("invalid port"); | |||||
// } | |||||
// String host = prop.getProperty("host"); | |||||
// String ledger = prop.getProperty("ledger"); | |||||
// String pubKey = prop.getProperty("pubKey"); | |||||
// String prvKey = prop.getProperty("prvKey"); | |||||
// String password = prop.getProperty("password"); | |||||
// String contractPath = prop.getProperty("contractPath"); | |||||
// | |||||
// | |||||
// if(StringUtils.isEmpty(host)){ | |||||
// logger.info("host不能为空"); | |||||
// return; | |||||
// } | |||||
// | |||||
// if(StringUtils.isEmpty(ledger)){ | |||||
// logger.info("ledger不能为空."); | |||||
// return; | |||||
// } | |||||
// if(StringUtils.isEmpty(pubKey)){ | |||||
// logger.info("pubKey不能为空."); | |||||
// return; | |||||
// } | |||||
// if(StringUtils.isEmpty(prvKey)){ | |||||
// logger.info("prvKey不能为空."); | |||||
// return; | |||||
// } | |||||
// if(StringUtils.isEmpty(contractPath)){ | |||||
// logger.info("contractPath不能为空."); | |||||
// return; | |||||
// } | |||||
// | |||||
// File contract = new File(contractPath); | |||||
// if (!contract.isFile()){ | |||||
// logger.info("文件"+contractPath+"不存在"); | |||||
// return; | |||||
// } | |||||
// byte[] contractBytes = FileUtils.readBytes(contractPath); | |||||
// | |||||
// | |||||
// PrivKey prv = KeyGenCommand.decodePrivKeyWithRawPassword(prvKey, password); | |||||
// PubKey pub = KeyGenCommand.decodePubKey(pubKey); | |||||
// BlockchainKeypair blockchainKeyPair = new BlockchainKeypair(pub, prv); | |||||
// HashDigest ledgerHash = new HashDigest(Base58Utils.decode(ledger)); | |||||
// | |||||
// StringBuffer sb = new StringBuffer(); | |||||
// sb.append("host:"+ host).append(",port:"+port).append(",ledgerHash:"+ledgerHash.toBase58()). | |||||
// append(",pubKey:"+pubKey).append(",prvKey:"+prv).append(",contractPath:"+contractPath); | |||||
// logger.info(sb.toString()); | |||||
// ContractDeployExeUtil.instance.deploy(host,port,ledgerHash, blockchainKeyPair, contractBytes); | |||||
// } | |||||
// | |||||
//} | |||||
// | |||||
// |
@@ -6,13 +6,9 @@ import com.github.javaparser.ast.ImportDeclaration; | |||||
import com.github.javaparser.ast.visitor.VoidVisitorAdapter; | import com.github.javaparser.ast.visitor.VoidVisitorAdapter; | ||||
import com.jd.blockchain.contract.ContractType; | import com.jd.blockchain.contract.ContractType; | ||||
import org.apache.commons.io.FileUtils; | import org.apache.commons.io.FileUtils; | ||||
import org.apache.maven.plugin.AbstractMojo; | |||||
import org.apache.maven.plugin.MojoExecutionException; | |||||
import org.apache.maven.plugins.annotations.Mojo; | |||||
import org.apache.maven.plugins.annotations.Parameter; | |||||
import org.apache.maven.plugin.MojoFailureException; | |||||
import org.apache.maven.plugin.logging.Log; | |||||
import org.apache.maven.project.MavenProject; | import org.apache.maven.project.MavenProject; | ||||
import org.slf4j.Logger; | |||||
import org.slf4j.LoggerFactory; | |||||
import java.io.File; | import java.io.File; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
@@ -24,32 +20,11 @@ import java.util.jar.Attributes; | |||||
import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||
import java.util.jar.JarFile; | import java.util.jar.JarFile; | ||||
import static com.jd.blockchain.contract.maven.ContractCheckMojo.CONTRACT_VERIFY; | |||||
import static com.jd.blockchain.contract.maven.ContractCompileMojo.JAR_DEPENDENCE; | |||||
import static com.jd.blockchain.utils.decompiler.utils.DecompilerUtils.decompileJarFile; | import static com.jd.blockchain.utils.decompiler.utils.DecompilerUtils.decompileJarFile; | ||||
import static com.jd.blockchain.utils.jar.ContractJarUtils.*; | import static com.jd.blockchain.utils.jar.ContractJarUtils.*; | ||||
/** | |||||
* 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 = CONTRACT_VERIFY) | |||||
public class ContractVerifyMojo extends AbstractMojo { | |||||
Logger LOG = LoggerFactory.getLogger(ContractVerifyMojo.class); | |||||
@Parameter(defaultValue = "${project}", required = true, readonly = true) | |||||
private MavenProject project; | |||||
/** | |||||
* jar's name; | |||||
*/ | |||||
@Parameter | |||||
private String finalName; | |||||
public class ContractResolveEngine { | |||||
private static final String JAVA_SUFFIX = ".java"; | private static final String JAVA_SUFFIX = ".java"; | ||||
@@ -66,19 +41,49 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
private static final String BLACK_NAME_LIST = "black.name.list"; | private static final String BLACK_NAME_LIST = "black.name.list"; | ||||
@Override | |||||
public void execute() throws MojoExecutionException { | |||||
private Log LOGGER; | |||||
private MavenProject project; | |||||
private String finalName; | |||||
public ContractResolveEngine(Log LOGGER, MavenProject project, String finalName) { | |||||
this.LOGGER = LOGGER; | |||||
this.project = project; | |||||
this.finalName = finalName; | |||||
} | |||||
public void compileAndVerify() throws MojoFailureException { | |||||
try { | try { | ||||
jarCopy(); | |||||
verify(compileCustomJar()); | |||||
} catch (IOException e) { | |||||
throw new MojoFailureException("IO Error : " + e.getMessage(), e); | |||||
} catch (MojoFailureException ex) { | |||||
throw ex; | |||||
} | |||||
} | |||||
File jarFile = copyAndManage(); | |||||
private void jarCopy() throws IOException { | |||||
String srcJarPath = project.getBuild().getDirectory() + | |||||
File.separator + finalName + "-" + JAR_DEPENDENCE + ".jar"; | |||||
String dstJarPath = project.getBuild().getDirectory() + | |||||
File.separator + finalName + ".jar"; | |||||
FileUtils.copyFile(new File(srcJarPath), new File(dstJarPath)); | |||||
} | |||||
private File compileCustomJar() throws IOException { | |||||
return copyAndManage(project, finalName); | |||||
} | |||||
private void verify(File jarFile) throws MojoFailureException { | |||||
try { | |||||
// 首先校验MainClass | // 首先校验MainClass | ||||
try { | try { | ||||
verifyMainClass(jarFile); | verifyMainClass(jarFile); | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
jarFile.delete(); | jarFile.delete(); | ||||
LOG.error(e.getMessage()); | |||||
LOGGER.error(e.getMessage()); | |||||
throw e; | throw e; | ||||
} | } | ||||
@@ -101,9 +106,13 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
boolean isOK = true; | boolean isOK = true; | ||||
for (String clazz : totalClassList) { | for (String clazz : totalClassList) { | ||||
LOGGER.debug(String.format("Verify Class[%s] start......", clazz)); | |||||
// 获取其包名 | // 获取其包名 | ||||
String packageName = packageName(clazz); | String packageName = packageName(clazz); | ||||
LOGGER.debug(String.format("Class[%s] 's package name = %s", clazz, packageName)); | |||||
// 包的名字黑名单,不能打包该类进入Jar包中,或者合约不能命名这样的名字 | // 包的名字黑名单,不能打包该类进入Jar包中,或者合约不能命名这样的名字 | ||||
boolean isNameBlack = false; | boolean isNameBlack = false; | ||||
for (ContractPackage blackName : blackNameList) { | for (ContractPackage blackName : blackNameList) { | ||||
@@ -116,7 +125,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
// 假设是黑名单则打印日志 | // 假设是黑名单则打印日志 | ||||
if (isNameBlack) { | if (isNameBlack) { | ||||
// 打印信息供检查 | // 打印信息供检查 | ||||
LOG.error(String.format("Class[%s]'s Package-Name belong to BlackNameList !!!", clazz)); | |||||
LOGGER.error(String.format("Class[%s]'s Package-Name belong to BlackNameList !!!", clazz)); | |||||
isOK = false; | isOK = false; | ||||
continue; | continue; | ||||
} | } | ||||
@@ -126,6 +135,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
boolean isNeedDelete = false; | boolean isNeedDelete = false; | ||||
if (!javaFile.exists()) { | if (!javaFile.exists()) { | ||||
LOGGER.debug(String.format("Class[%s] -> Java[%s] is not exist, start decompile ...", clazz, jarFile.getPath())); | |||||
// 表明不是项目中的内容,需要通过反编译获取该文件 | // 表明不是项目中的内容,需要通过反编译获取该文件 | ||||
String source = null; | String source = null; | ||||
try { | try { | ||||
@@ -134,15 +144,18 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
throw new IllegalStateException(); | throw new IllegalStateException(); | ||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LOG.warn(String.format("Decompile Jar[%s]->Class[%s] Fail !!!", jarFile.getPath(), clazz)); | |||||
LOGGER.warn(String.format("Decompile Jar[%s]->Class[%s] Fail !!!", jarFile.getPath(), clazz)); | |||||
} | } | ||||
// 将source写入Java文件 | // 将source写入Java文件 | ||||
File sourceTempJavaFile = new File(tempPath(codeBaseDir, clazz)); | File sourceTempJavaFile = new File(tempPath(codeBaseDir, clazz)); | ||||
FileUtils.writeStringToFile(sourceTempJavaFile, source == null ? "" : source); | FileUtils.writeStringToFile(sourceTempJavaFile, source == null ? "" : source); | ||||
javaFile = sourceTempJavaFile; | javaFile = sourceTempJavaFile; | ||||
isNeedDelete = true; | isNeedDelete = true; | ||||
} else { | |||||
LOGGER.debug(String.format("Class[%s] -> Java[%s] is exist", clazz, jarFile.getPath())); | |||||
} | } | ||||
LOGGER.info(String.format("Parse Java File [%s] start......", javaFile.getPath())); | |||||
// 解析文件中的内容 | // 解析文件中的内容 | ||||
CompilationUnit compilationUnit = JavaParser.parse(javaFile); | CompilationUnit compilationUnit = JavaParser.parse(javaFile); | ||||
@@ -154,13 +167,14 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
if (!imports.isEmpty()) { | if (!imports.isEmpty()) { | ||||
for (String importClass : imports) { | for (String importClass : imports) { | ||||
LOGGER.debug(String.format("Class[%s] read import -> [%s]", clazz, importClass)); | |||||
if (importClass.endsWith("*")) { | if (importClass.endsWith("*")) { | ||||
// 导入的是包 | // 导入的是包 | ||||
for (ContractPackage blackPackage : blackPackageList) { | for (ContractPackage blackPackage : blackPackageList) { | ||||
String importPackageName = importClass.substring(0, importClass.length() - 2); | String importPackageName = importClass.substring(0, importClass.length() - 2); | ||||
if (verifyPackage(importPackageName, blackPackage)) { | if (verifyPackage(importPackageName, blackPackage)) { | ||||
// 打印信息供检查 | // 打印信息供检查 | ||||
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass)); | |||||
LOGGER.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass)); | |||||
isOK = false; | isOK = false; | ||||
break; | break; | ||||
} | } | ||||
@@ -169,13 +183,13 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
// 导入的是具体的类,则判断类黑名单 + 包黑名单 | // 导入的是具体的类,则判断类黑名单 + 包黑名单 | ||||
if (blackClassSet.contains(importClass)) { | if (blackClassSet.contains(importClass)) { | ||||
// 包含导入类,该方式无法通过验证 | // 包含导入类,该方式无法通过验证 | ||||
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackClassList !!!", clazz, importClass)); | |||||
LOGGER.error(String.format("Class[%s]'s import class [%s] belong to BlackClassList !!!", clazz, importClass)); | |||||
isOK = false; | isOK = false; | ||||
} else { | } else { | ||||
// 判断导入的该类与黑名单导入包的对应关系 | // 判断导入的该类与黑名单导入包的对应关系 | ||||
for (ContractPackage blackPackage : blackPackageList) { | for (ContractPackage blackPackage : blackPackageList) { | ||||
if (verifyClass(importClass, blackPackage)) { | if (verifyClass(importClass, blackPackage)) { | ||||
LOG.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass)); | |||||
LOGGER.error(String.format("Class[%s]'s import class [%s] belong to BlackPackageList !!!", clazz, importClass)); | |||||
isOK = false; | isOK = false; | ||||
break; | break; | ||||
} | } | ||||
@@ -187,6 +201,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
if (isNeedDelete) { | if (isNeedDelete) { | ||||
javaFile.delete(); | javaFile.delete(); | ||||
} | } | ||||
LOGGER.debug(String.format("Verify Class[%s] end......", clazz)); | |||||
} | } | ||||
if (!isOK) { | if (!isOK) { | ||||
// 需要将该Jar删除 | // 需要将该Jar删除 | ||||
@@ -198,19 +213,21 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
throw new IllegalStateException("There is none class !!!"); | throw new IllegalStateException("There is none class !!!"); | ||||
} | } | ||||
} catch (Exception e) { | } catch (Exception e) { | ||||
LOG.error(e.getMessage()); | |||||
throw new MojoExecutionException(e.getMessage()); | |||||
LOGGER.error(e.getMessage()); | |||||
throw new MojoFailureException(e.getMessage(), e); | |||||
} | } | ||||
} | } | ||||
private void verifyMainClass(File jarFile) throws Exception { | private void verifyMainClass(File jarFile) throws Exception { | ||||
// 加载main-class,开始校验类型 | // 加载main-class,开始校验类型 | ||||
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass start...", jarFile.getName())); | |||||
URL jarURL = jarFile.toURI().toURL(); | URL jarURL = jarFile.toURI().toURL(); | ||||
ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader()); | ClassLoader classLoader = new URLClassLoader(new URL[]{jarURL}, this.getClass().getClassLoader()); | ||||
Attributes m = new JarFile(jarFile).getManifest().getMainAttributes(); | Attributes m = new JarFile(jarFile).getManifest().getMainAttributes(); | ||||
String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS); | String contractMainClass = m.getValue(Attributes.Name.MAIN_CLASS); | ||||
Class mainClass = classLoader.loadClass(contractMainClass); | Class mainClass = classLoader.loadClass(contractMainClass); | ||||
ContractType.resolve(mainClass); | ContractType.resolve(mainClass); | ||||
LOGGER.debug(String.format("Verify Jar [%s] 's MainClass end...", jarFile.getName())); | |||||
} | } | ||||
private List<ContractPackage> blackNameList(Properties config) { | private List<ContractPackage> blackNameList(Properties config) { | ||||
@@ -223,6 +240,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
if (attrProp != null && attrProp.length() > 0) { | if (attrProp != null && attrProp.length() > 0) { | ||||
String[] attrPropArray = attrProp.split(","); | String[] attrPropArray = attrProp.split(","); | ||||
for (String attr : attrPropArray) { | for (String attr : attrPropArray) { | ||||
LOGGER.info(String.format("Config [%s] -> [%s]", BLACK_CLASS_LIST, attr)); | |||||
blackClassSet.add(attr.trim()); | blackClassSet.add(attr.trim()); | ||||
} | } | ||||
} | } | ||||
@@ -239,6 +257,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
if (attrProp != null || attrProp.length() > 0) { | if (attrProp != null || attrProp.length() > 0) { | ||||
String[] attrPropArray = attrProp.split(","); | String[] attrPropArray = attrProp.split(","); | ||||
for (String attr : attrPropArray) { | for (String attr : attrPropArray) { | ||||
LOGGER.info(String.format("Config [%s] -> [%s]", attrName, attr)); | |||||
list.add(new ContractPackage(attr)); | list.add(new ContractPackage(attr)); | ||||
} | } | ||||
} | } | ||||
@@ -310,7 +329,7 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
return packageName.replaceAll("/", "."); | return packageName.replaceAll("/", "."); | ||||
} | } | ||||
private File copyAndManage() throws IOException { | |||||
private File copyAndManage(MavenProject project, String finalName) throws IOException { | |||||
// 首先将Jar包转换为指定的格式 | // 首先将Jar包转换为指定的格式 | ||||
String srcJarPath = project.getBuild().getDirectory() + | String srcJarPath = project.getBuild().getDirectory() + | ||||
File.separator + finalName + ".jar"; | File.separator + finalName + ".jar"; | ||||
@@ -320,8 +339,10 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
File srcJar = new File(srcJarPath), dstJar = new File(dstJarPath); | File srcJar = new File(srcJarPath), dstJar = new File(dstJarPath); | ||||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copying", srcJarPath, dstJarPath)); | |||||
// 首先进行Copy处理 | // 首先进行Copy处理 | ||||
copy(srcJar, dstJar); | copy(srcJar, dstJar); | ||||
LOGGER.debug(String.format("Jar from [%s] to [%s] Copied", srcJarPath, dstJarPath)); | |||||
byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8); | byte[] txtBytes = contractMF(FileUtils.readFileToByteArray(dstJar)).getBytes(StandardCharsets.UTF_8); | ||||
@@ -376,24 +397,6 @@ public class ContractVerifyMojo extends AbstractMojo { | |||||
private List<String> importClasses = new ArrayList<>(); | private List<String> importClasses = new ArrayList<>(); | ||||
// @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 */ | |||||
// super.visit(n, arg); | |||||
// } | |||||
// | |||||
// @Override | |||||
// public void visit(ClassOrInterfaceDeclaration n, Void arg) { | |||||
// super.visit(n, arg); | |||||
// } | |||||
// | |||||
// @Override | |||||
// public void visit(PackageDeclaration n, Void arg) { | |||||
// super.visit(n, arg); | |||||
// } | |||||
@Override | @Override | ||||
public void visit(ImportDeclaration n, Void arg) { | public void visit(ImportDeclaration n, Void arg) { | ||||
importClasses.add(parseClass(n.toString())); | importClasses.add(parseClass(n.toString())); |
@@ -1,19 +0,0 @@ | |||||
#PROJECT_BASE_DIR | |||||
PROJECT_BASE_DIR=E:\\gitCode\\block\\prototype\\ | |||||
#LEDGER_BASE_CLASS_PATH | |||||
LEDGER_BASE_CLASS_PATH=E:\\gitCode\\block\\prototype\\libs\\ | |||||
#deploy and execute the contract; | |||||
cParam=com.jd.blockchain.contract.AssetContract3 | |||||
sParam=E:\\gitCode\\block\\prototype\\source\\sdk\\contract-sample\\src\\main\\java\\ | |||||
eParam=utf-8 | |||||
oParam=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\src\\test\\resources\\ | |||||
host=127.0.0.1 | |||||
port=8081 | |||||
event = issue-asset | |||||
ownerPassword=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\ownerPassword.txt | |||||
ownerPubPath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\jd-com.pub | |||||
ownerPrvPath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\conf\\jd-com.priv | |||||
chainCodePath=E:\\gitCode\\block\\prototype\\source\\contract\\contract-maven-plugin\\src\\test\\resources\\AssetContract3.contract | |||||
ledgerHash=6FEQDTQMnBGANpfX4haXuWHKHw5cZ6P1h2ocqwckYBxp4 | |||||
contractArgs=101##999##abc |
@@ -1,21 +1,21 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.contract.maven.ContractDeployMojo; | |||||
import java.lang.reflect.Field; | |||||
/** | |||||
* for contract deploy and exe; | |||||
* @Author zhaogw | |||||
* @Date 2018/11/02 09:06 | |||||
*/ | |||||
public class ContractDeployMojoTest { | |||||
private ContractDeployMojo contractDeployMojo = new ContractDeployMojo(); | |||||
private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException, IllegalAccessException { | |||||
Field field = contractDeployMojo.getClass().getDeclaredField(fieldName);//name为类Instance中的private属性 | |||||
field.setAccessible(true);//=true,可访问私有变量。 | |||||
Class<?> typeClass = field.getType(); | |||||
field.set(contractDeployMojo, objValue); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.ledger; | |||||
// | |||||
//import com.jd.blockchain.contract.maven.ContractDeployMojo; | |||||
// | |||||
//import java.lang.reflect.Field; | |||||
// | |||||
///** | |||||
// * for contract deploy and exe; | |||||
// * @Author zhaogw | |||||
// * @Date 2018/11/02 09:06 | |||||
// */ | |||||
//public class ContractDeployMojoTest { | |||||
// private ContractDeployMojo contractDeployMojo = new ContractDeployMojo(); | |||||
// | |||||
// private void fieldHandle(String fieldName,Object objValue) throws NoSuchFieldException, IllegalAccessException { | |||||
// Field field = contractDeployMojo.getClass().getDeclaredField(fieldName);//name为类Instance中的private属性 | |||||
// field.setAccessible(true);//=true,可访问私有变量。 | |||||
// Class<?> typeClass = field.getType(); | |||||
// field.set(contractDeployMojo, objValue); | |||||
// } | |||||
//} |
@@ -1,50 +1,50 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import org.apache.maven.model.Build; | |||||
import org.apache.maven.project.MavenProject; | |||||
import org.junit.Test; | |||||
import org.springframework.core.io.ClassPathResource; | |||||
import java.io.File; | |||||
public class ContractTestBase { | |||||
public static MavenProject mavenProjectInit() { | |||||
MavenProject mavenProject = new MavenProject(); | |||||
mavenProject.setBuild(buildInit()); | |||||
mavenProject.setFile(file()); | |||||
return mavenProject; | |||||
} | |||||
public static File file() { | |||||
String resDir = resourceDir(); | |||||
File file = new File(resDir); | |||||
String path = file.getParentFile().getParentFile().getPath(); | |||||
return new File(path + File.separator + "src"); | |||||
} | |||||
public static Build buildInit() { | |||||
Build build = new Build(); | |||||
build.setDirectory(resourceDir()); | |||||
return build; | |||||
} | |||||
public static String resourceDir() { | |||||
try { | |||||
ClassPathResource classPathResource = new ClassPathResource("complex.jar"); | |||||
return classPathResource.getFile().getParentFile().getPath(); | |||||
} catch (Exception e) { | |||||
throw new IllegalStateException(e); | |||||
} | |||||
} | |||||
@Test | |||||
public void testResourceDir() { | |||||
System.out.println(resourceDir()); | |||||
} | |||||
@Test | |||||
public void testFile() { | |||||
System.out.println(file().getPath()); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.ledger; | |||||
// | |||||
//import org.apache.maven.model.Build; | |||||
//import org.apache.maven.project.MavenProject; | |||||
//import org.junit.Test; | |||||
//import org.springframework.core.io.ClassPathResource; | |||||
// | |||||
//import java.io.File; | |||||
// | |||||
//public class ContractTestBase { | |||||
// | |||||
// public static MavenProject mavenProjectInit() { | |||||
// MavenProject mavenProject = new MavenProject(); | |||||
// mavenProject.setBuild(buildInit()); | |||||
// mavenProject.setFile(file()); | |||||
// return mavenProject; | |||||
// } | |||||
// | |||||
// public static File file() { | |||||
// String resDir = resourceDir(); | |||||
// File file = new File(resDir); | |||||
// String path = file.getParentFile().getParentFile().getPath(); | |||||
// return new File(path + File.separator + "src"); | |||||
// } | |||||
// | |||||
// public static Build buildInit() { | |||||
// Build build = new Build(); | |||||
// build.setDirectory(resourceDir()); | |||||
// return build; | |||||
// } | |||||
// | |||||
// public static String resourceDir() { | |||||
// try { | |||||
// ClassPathResource classPathResource = new ClassPathResource("complex.jar"); | |||||
// return classPathResource.getFile().getParentFile().getPath(); | |||||
// } catch (Exception e) { | |||||
// throw new IllegalStateException(e); | |||||
// } | |||||
// } | |||||
// | |||||
// @Test | |||||
// public void testResourceDir() { | |||||
// System.out.println(resourceDir()); | |||||
// } | |||||
// | |||||
// @Test | |||||
// public void testFile() { | |||||
// System.out.println(file().getPath()); | |||||
// } | |||||
//} |
@@ -1,28 +1,28 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.contract.maven.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( "contractVerify", pom ); | |||||
assertNotNull( myMojo ); | |||||
myMojo.execute(); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.ledger; | |||||
// | |||||
//import com.jd.blockchain.contract.maven.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( "contractVerify", pom ); | |||||
// assertNotNull( myMojo ); | |||||
// myMojo.execute(); | |||||
// } | |||||
//} |
@@ -1,47 +1,47 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import com.jd.blockchain.contract.maven.ContractVerifyMojo; | |||||
import org.apache.maven.project.MavenProject; | |||||
import org.junit.Before; | |||||
import org.junit.Test; | |||||
import java.lang.reflect.Field; | |||||
import static com.jd.blockchain.ledger.ContractTestBase.mavenProjectInit; | |||||
public class ContractVerifyTest_ { | |||||
private MavenProject project; | |||||
private String finalName; | |||||
@Before | |||||
public void testInit() { | |||||
project = mavenProjectInit(); | |||||
finalName = "complex"; | |||||
} | |||||
@Test | |||||
public void test() throws Exception { | |||||
ContractVerifyMojo contractVerifyMojo = contractVerifyMojoConf(); | |||||
contractVerifyMojo.execute(); | |||||
} | |||||
private ContractVerifyMojo contractVerifyMojoConf() throws Exception { | |||||
ContractVerifyMojo contractVerifyMojo = new ContractVerifyMojo(); | |||||
// 为不影响其内部结构,通过反射进行私有变量赋值 | |||||
Class<?> clazz = contractVerifyMojo.getClass(); | |||||
Field projectField = clazz.getDeclaredField("project"); | |||||
Field finalNameField = clazz.getDeclaredField("finalName"); | |||||
// 更新权限 | |||||
projectField.setAccessible(true); | |||||
finalNameField.setAccessible(true); | |||||
// 设置具体值 | |||||
projectField.set(contractVerifyMojo, project); | |||||
finalNameField.set(contractVerifyMojo, finalName); | |||||
return contractVerifyMojo; | |||||
} | |||||
} | |||||
//package com.jd.blockchain.ledger; | |||||
// | |||||
//import com.jd.blockchain.contract.maven.ContractVerifyMojo; | |||||
//import org.apache.maven.project.MavenProject; | |||||
//import org.junit.Before; | |||||
//import org.junit.Test; | |||||
// | |||||
//import java.lang.reflect.Field; | |||||
// | |||||
//import static com.jd.blockchain.ledger.ContractTestBase.mavenProjectInit; | |||||
// | |||||
//public class ContractVerifyTest_ { | |||||
// | |||||
// private MavenProject project; | |||||
// | |||||
// private String finalName; | |||||
// | |||||
// @Before | |||||
// public void testInit() { | |||||
// project = mavenProjectInit(); | |||||
// finalName = "complex"; | |||||
// } | |||||
// | |||||
// @Test | |||||
// public void test() throws Exception { | |||||
// ContractVerifyMojo contractVerifyMojo = contractVerifyMojoConf(); | |||||
// contractVerifyMojo.execute(); | |||||
// } | |||||
// | |||||
// private ContractVerifyMojo contractVerifyMojoConf() throws Exception { | |||||
// ContractVerifyMojo contractVerifyMojo = new ContractVerifyMojo(); | |||||
// // 为不影响其内部结构,通过反射进行私有变量赋值 | |||||
// Class<?> clazz = contractVerifyMojo.getClass(); | |||||
// Field projectField = clazz.getDeclaredField("project"); | |||||
// Field finalNameField = clazz.getDeclaredField("finalName"); | |||||
// | |||||
// // 更新权限 | |||||
// projectField.setAccessible(true); | |||||
// finalNameField.setAccessible(true); | |||||
// | |||||
// // 设置具体值 | |||||
// projectField.set(contractVerifyMojo, project); | |||||
// finalNameField.set(contractVerifyMojo, finalName); | |||||
// | |||||
// return contractVerifyMojo; | |||||
// } | |||||
//} |
@@ -1,67 +1,67 @@ | |||||
package com.jd.blockchain.ledger; | |||||
import org.apache.maven.model.Build; | |||||
import org.apache.maven.model.Model; | |||||
import org.apache.maven.model.io.xpp3.MavenXpp3Reader; | |||||
import org.apache.maven.plugin.testing.stubs.MavenProjectStub; | |||||
import org.codehaus.plexus.util.ReaderFactory; | |||||
import java.io.File; | |||||
import java.util.ArrayList; | |||||
import java.util.List; | |||||
/** | |||||
* @author zhaogw | |||||
* date 2019/6/4 18:33 | |||||
*/ | |||||
public class MyProjectStub extends MavenProjectStub | |||||
{ | |||||
/** | |||||
* Default constructor | |||||
*/ | |||||
public MyProjectStub() | |||||
{ | |||||
MavenXpp3Reader pomReader = new MavenXpp3Reader(); | |||||
Model model; | |||||
try | |||||
{ | |||||
model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) ); | |||||
setModel( model ); | |||||
} | |||||
catch ( Exception e ) | |||||
{ | |||||
throw new RuntimeException( e ); | |||||
} | |||||
setGroupId( model.getGroupId() ); | |||||
setArtifactId( model.getArtifactId() ); | |||||
setVersion( model.getVersion() ); | |||||
setName( model.getName() ); | |||||
setUrl( model.getUrl() ); | |||||
setPackaging( model.getPackaging() ); | |||||
Build build = new Build(); | |||||
build.setFinalName( model.getArtifactId() ); | |||||
build.setDirectory( getBasedir() + "/target" ); | |||||
build.setSourceDirectory( getBasedir() + "/src/main/java" ); | |||||
build.setOutputDirectory( getBasedir() + "/target/classes" ); | |||||
build.setTestSourceDirectory( getBasedir() + "/src/test/java" ); | |||||
build.setTestOutputDirectory( getBasedir() + "/target/test-classes" ); | |||||
setBuild( build ); | |||||
List compileSourceRoots = new ArrayList(); | |||||
compileSourceRoots.add( getBasedir() + "/src/main/java" ); | |||||
setCompileSourceRoots( compileSourceRoots ); | |||||
List testCompileSourceRoots = new ArrayList(); | |||||
testCompileSourceRoots.add( getBasedir() + "/src/test/java" ); | |||||
setTestCompileSourceRoots( testCompileSourceRoots ); | |||||
} | |||||
/** {@inheritDoc} */ | |||||
public File getBasedir() | |||||
{ | |||||
return new File( super.getBasedir() + "/src/test/resources/project-to-test/" ); | |||||
} | |||||
} | |||||
//package com.jd.blockchain.ledger; | |||||
// | |||||
//import org.apache.maven.model.Build; | |||||
//import org.apache.maven.model.Model; | |||||
//import org.apache.maven.model.io.xpp3.MavenXpp3Reader; | |||||
//import org.apache.maven.plugin.testing.stubs.MavenProjectStub; | |||||
//import org.codehaus.plexus.util.ReaderFactory; | |||||
// | |||||
//import java.io.File; | |||||
//import java.util.ArrayList; | |||||
//import java.util.List; | |||||
// | |||||
///** | |||||
// * @author zhaogw | |||||
// * date 2019/6/4 18:33 | |||||
// */ | |||||
// | |||||
//public class MyProjectStub extends MavenProjectStub | |||||
//{ | |||||
// /** | |||||
// * Default constructor | |||||
// */ | |||||
// public MyProjectStub() | |||||
// { | |||||
// MavenXpp3Reader pomReader = new MavenXpp3Reader(); | |||||
// Model model; | |||||
// try | |||||
// { | |||||
// model = pomReader.read( ReaderFactory.newXmlReader( new File( getBasedir(), "pom.xml" ) ) ); | |||||
// setModel( model ); | |||||
// } | |||||
// catch ( Exception e ) | |||||
// { | |||||
// throw new RuntimeException( e ); | |||||
// } | |||||
// | |||||
// setGroupId( model.getGroupId() ); | |||||
// setArtifactId( model.getArtifactId() ); | |||||
// setVersion( model.getVersion() ); | |||||
// setName( model.getName() ); | |||||
// setUrl( model.getUrl() ); | |||||
// setPackaging( model.getPackaging() ); | |||||
// | |||||
// Build build = new Build(); | |||||
// build.setFinalName( model.getArtifactId() ); | |||||
// build.setDirectory( getBasedir() + "/target" ); | |||||
// build.setSourceDirectory( getBasedir() + "/src/main/java" ); | |||||
// build.setOutputDirectory( getBasedir() + "/target/classes" ); | |||||
// build.setTestSourceDirectory( getBasedir() + "/src/test/java" ); | |||||
// build.setTestOutputDirectory( getBasedir() + "/target/test-classes" ); | |||||
// setBuild( build ); | |||||
// | |||||
// List compileSourceRoots = new ArrayList(); | |||||
// compileSourceRoots.add( getBasedir() + "/src/main/java" ); | |||||
// setCompileSourceRoots( compileSourceRoots ); | |||||
// | |||||
// List testCompileSourceRoots = new ArrayList(); | |||||
// testCompileSourceRoots.add( getBasedir() + "/src/test/java" ); | |||||
// setTestCompileSourceRoots( testCompileSourceRoots ); | |||||
// } | |||||
// | |||||
// /** {@inheritDoc} */ | |||||
// public File getBasedir() | |||||
// { | |||||
// return new File( super.getBasedir() + "/src/test/resources/project-to-test/" ); | |||||
// } | |||||
//} |