2021SC@SDUSC
智能合约
1. 简介
JD Chain 智能合约系统由合约代码语言、合约引擎、合约账户、合约开发框架、合约开发插件五部分组成。
合同代码语言是编写智能合同的编程语言,合同引擎是解释和执行合同代码的虚拟机。
JD Chain 合同代码以合同账户的形式管理。部署在链上的合同代码需要与唯一的公钥相关联,并生成与公钥对应的区块链账户地址,并在账本中注册为合同账户。在执行之前,系统从账本中读取合同代码,并将其加载到合同引擎中,交易执行器调用合同引擎触发合同执行。
JD Chain 账本定义了一组标准的账本操作指令。合同代码的执行过程本质上是将一系列操作指令序列输出到账簿中,这些指令改变了账簿中的数据,形成了合同执行的最终结果。
合同开发框架定义了合同代码开发中需要依赖的一组编程接口和类库。合同开发插件提供了更方便和IDE集成的合约编译、部署工具,可以简化操作,并与持续集成过程结合。
JD Chain 以 Java 以合同代码语言为基础的语言 JVM 构建的安全沙箱。为实现与主流应用开发模式的无缝兼容, JD Chain 支持以 Maven 管理合同代码的项目,并提供相应的项目 maven 简化合同的编译和部署。
智能合同是计算机可以执行的合同/协议。与现实生活中的合同不同,它是由自然语言编写和约定相关方的权利和义务的。智能合同是以合同代码语言编写的,以合同代码的形式存在和执行。合同/协议的相关条款信息通过账簿中的数据状态表示。合同代码的操作过程反映了合同/协议条款的执行情况,并记录了相应的结果。
2. 快速入门
2.1. 为环境发展做好准备
按照正常的 Java 为应用开发环境要求做好准备 Maven 作为代码工程的施工管理工具,没有其他特殊要求。
检查 JDK 版本不低于 1.8 ,Maven 版本不低于 3.0。
2.2. 创建合同代码工程
创造一个普通的 Java Maven 工程,打开 pom.xml 把 packaging 设为 contract .
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>your.group.id</groupId> <artifactId>your.project</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 声明称为合同代码工程,编译输出扩展称为".car"合约代码 --> <packaging>contract</packaging> <dependencies> <!-- 依赖合同项目 --> </dependencies> <build> <plugins> <!-- 合约项目的插件 -->
</plugins>
</build>
</project>
2.3. 加入合约开发依赖
在合约代码工程 pom.xml 加入对合约开发 SDK 的依赖:
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-starter</artifactId>
<version>${jdchain.version}</version>
</dependency>
2.4. 加入合约插件
在合约代码工程的 pom.xml 加入 contract-maven-plugin 插件:
<plugin>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-maven-plugin</artifactId>
<version>${jdchain.version}</version>
<extensions>true</extensions>
</plugin>
完整的 pom.xml 如下:
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>your.group.id</groupId>
<artifactId>your.project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- 声明为合约代码工程,编译输出扩展名为".car"合约代码 -->
<packaging>contract</packaging>
<properties>
<jdchain.version>1.4.2.RELEASE</jdchain.version>
</properties>
<dependencies>
<!-- 合约项目的依赖 -->
<dependency>
<groupId>com.jd.blockchain</groupId>
<artifactId>contract-starter</artifactId>
<version>${jdchain.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<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>com.jd.blockchain</groupId>
<artifactId>contract-maven-plugin</artifactId>
<version>${jdchain.version}</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>
2.5.2.
/** * 声明合约接口; **/
@Contract
public interface AssetContract {
@ContractEvent(name = "transfer")
String transfer(String address, String from, String to, long amount);
}
2.5.3.
/** * 实现合约; * * 实现 EventProcessingAware 接口是可选的,目的获得 ContractEventContext 上下文对象, * 通过该对象可以进行账本操作; */
public class AssetContractImpl implements AssetContract, EventProcessingAware {
// 合约事件上下文;
private ContractEventContext eventContext;
/** * 执行交易请求中对 AssetContract 合约的 transfer 调用操作; */
public String transfer(String address, String from, String to, long amount) {
//当前账本的哈希;
HashDigest ledgerHash = eventContext.getCurrentLedgerHash();
//当前账本上下文;
LedgerContext ledgerContext = eventContext.getLedger();
//做操作;
// ledgerContext.
//返回合约操作的结果;
return "success";
}
/** * 准备执行交易中的合约调用操作; */
@Override
public void beforeEvent(ContractEventContext eventContext) {
this.eventContext = eventContext;
}
/** * 完成执行交易中的合约调用操作; */
@Override
public void postEvent(ContractEventContext eventContext, Exception error) {
this.eventContext = null;
}
}
:
ContractEventContext中getUncommittedLedger方法可访问执行中的未提交区块数据,此方法的合理使用可以解决客户并发调用合约方法涉及数据版本/事件序列冲突的问题。
/** * 当前包含未提交区块数据账本查询上下文; */
LedgerQueryService getUncommittedLedger();
ContractEventContext中getLedger方法访问的是链上已提交的最新区块数据,不包含未提交交易,所以存在未提交交易中多个合约方法调用操作间数据不可见,导致并发时数据版本等冲突问题。
/** * 账本操作上下文; */
LedgerContext getLedger();
合约方法中对账本的操作通过调用LedgerContext中相关方法,可参照示例合约
2.6. 编译打包合约代码
合约代码工程的编译打包操作与普通的 maven 工程是相同的,在工程的根目录下输入以下命令:
mvn clean package
执行成功之后,在 target 目录中输出合约代码文件 <project-name>.<version>.car 。
如果合约代码加入了除 com.jd.blockchain:contract-starter 之外的其它依赖,默认配置下,第三方依赖包将与 .car 文件一起打包一起部署。