You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

ReadME.MD 10 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # 合约编译插件使用教程
  2. ### 1、maven引入
  3. 在pom.xml文件中引入合约编译插件:
  4. ```xml
  5. <plugin>
  6. <groupId>com.jd.blockchain</groupId>
  7. <artifactId>contract-maven-plugin</artifactId>
  8. <version>1.0.0.RELEASE</version>
  9. <executions>
  10. <execution>
  11. <id>make-contract</id>
  12. <phase>package</phase>
  13. <goals>
  14. <goal>compile</goal>
  15. </goals>
  16. </execution>
  17. </executions>
  18. <configuration>
  19. <archive>
  20. <manifest>
  21. <mainClass>com.jd.chain.contracts.ContractTestInfImpl</mainClass>
  22. </manifest>
  23. </archive>
  24. <finalName>contract</finalName>
  25. </configuration>
  26. </plugin>
  27. ```
  28. 需要说明的几点如下:
  29. + 1)version:请根据实际JDChain发布版本确认,不同版本会有区别;
  30. + 2)executions->execution->id:该值请随意指定;
  31. + 3)executions->execution->phase:建议使用package及其后续阶段(若不了解phase含义,请自行查阅相关信息);
  32. + 4)executions->execution->goals->goal:必须使用compile;
  33. + 5)mainClass:必填,该类为需要发布的合约执行类(注意此处是类,不是接口),必须正确配置;
  34. + 6)finalName:必填,最终在编译正常的情况下,会产生{finalName}-JDChain-Contract.jar文件,只有该文件是可以发布到JDChain的合约包;
  35. ### 2、执行命令
  36. 使用mvn执行命令,下面两种方式均可:
  37. 方式一:只执行contract插件命令
  38. ```shell
  39. mvn clean compile contract:compile
  40. ```
  41. 方式二:直接执行打包命令:
  42. ```shell
  43. mvn clean package
  44. ```
  45. ### 3、合约编写要求
  46. 合约的执行结果会对整条链产生比较深刻的影响,为了使用户能够更好、更合理的使用合约,目前JDChain约定合约编写规则包括以下几点:
  47. (违反其中任何一点都可能导致合约编译失败,但即使合约编译通过也不能保证合约可百分百运行正常)
  48. + 1)合约工程必须引入com.jd.blockchain:sdk-pack:该包中有合约正常编写需要使用的基本类;
  49. + 2)com.jd.blockchain:sdk-pack的scope必须定义为provided;
  50. + 3)合约发布必须通过合约编译插件进行打包:合约编译插件不但会对Jar包进行校验,同时也会加入JDChain独有的特征,只有具有该特征的Jar才能正常发布;
  51. + 4)合约中严禁使用随机数、IO、NIO等操作;
  52. + 5)合约打包时,请使用<scope>provided</scope>排除常用的工具包,例如FastJson、apache下的一些工具包等;
  53. + 6)合约必须有一个接口和该接口的实现类,详细要求如下:
  54. - a. 接口必须有@Contract注解;
  55. - b. 接口的可调用方法上必须有@ContractEvent注解,且每个注解中的name属性不能重复;
  56. - c. 合约方法支持入参和返回值,其主要包括所有基本类型;
  57. ### 4、合约案例
  58. #### 4.1、代码实例
  59. 以下是一个可创建银行账户,指定具体金额,并可以转账的合约代码(逻辑较简单,仅供参考):
  60. 合约接口代码如下:
  61. ```java
  62. package com.jd.chain.contract;
  63. @Contract
  64. public interface TransferContract {
  65. @ContractEvent(name = "create")
  66. String create(String address, String account, long money);
  67. @ContractEvent(name = "transfer")
  68. String transfer(String address, String from, String to, long money);
  69. @ContractEvent(name = "read")
  70. long read(String address, String account);
  71. @ContractEvent(name = "readAll")
  72. String readAll(String address, String account);
  73. }
  74. ```
  75. 合约实现类代码如下:
  76. ```java
  77. package com.jd.chain.contract;
  78. import com.alibaba.fastjson.JSON;
  79. import com.jd.blockchain.crypto.HashDigest;
  80. import com.jd.blockchain.ledger.KVDataEntry;
  81. import com.jd.blockchain.ledger.KVDataVO;
  82. import com.jd.blockchain.ledger.KVInfoVO;
  83. public class TransferContractImpl implements EventProcessingAware, TransferContract {
  84. private ContractEventContext eventContext;
  85. private HashDigest ledgerHash;
  86. @Override
  87. public String create(String address, String account, long money) {
  88. KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
  89. // 肯定有返回值,但若不存在则返回version=-1
  90. if (kvDataEntries != null && kvDataEntries.length > 0) {
  91. long currVersion = kvDataEntries[0].getVersion();
  92. if (currVersion > -1) {
  93. throw new IllegalStateException(String.format("%s -> %s already have created !!!", address, account));
  94. }
  95. eventContext.getLedger().dataAccount(address).setInt64(account, money, -1L);
  96. } else {
  97. throw new IllegalStateException(String.format("Ledger[%s] inner Error !!!", ledgerHash.toBase58()));
  98. }
  99. return String.format("DataAccountAddress[%s] -> Create(By Contract Operation) Account = %s and Money = %s Success!!! \r\n",
  100. address, account, money);
  101. }
  102. @Override
  103. public String transfer(String address, String from, String to, long money) {
  104. // 首先查询余额
  105. KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, from, to);
  106. if (kvDataEntries == null || kvDataEntries.length != 2) {
  107. throw new IllegalStateException(String.format("%s -> %s - %s may be not created !!!", address, from, to));
  108. } else {
  109. // 判断from账号中钱数量是否足够
  110. long fromMoney = 0L, toMoney = 0L, fromVersion = 0L, toVersion = 0L;
  111. for (KVDataEntry kvDataEntry : kvDataEntries) {
  112. if (kvDataEntry.getKey().equals(from)) {
  113. fromMoney = (long) kvDataEntry.getValue();
  114. fromVersion = kvDataEntry.getVersion();
  115. } else {
  116. toMoney = (long) kvDataEntry.getValue();
  117. toVersion = kvDataEntry.getVersion();
  118. }
  119. }
  120. if (fromMoney < money) {
  121. throw new IllegalStateException(String.format("%s -> %s not have enough money !!!", address, from));
  122. }
  123. long fromNewMoney = fromMoney - money;
  124. long toNewMoney = toMoney + money;
  125. // 重新设置
  126. eventContext.getLedger().dataAccount(address).setInt64(from, fromNewMoney, fromVersion);
  127. eventContext.getLedger().dataAccount(address).setInt64(to, toNewMoney, toVersion);
  128. }
  129. return String.format("DataAccountAddress[%s] transfer from [%s] to [%s] and [money = %s] Success !!!", address, from, to, money);
  130. }
  131. @Override
  132. public long read(String address, String account) {
  133. KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
  134. if (kvDataEntries == null || kvDataEntries.length == 0) {
  135. return -1;
  136. }
  137. return (long)kvDataEntries[0].getValue();
  138. }
  139. @Override
  140. public String readAll(String address, String account) {
  141. KVDataEntry[] kvDataEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, account);
  142. // 获取最新的版本号
  143. if (kvDataEntries == null || kvDataEntries.length == 0) {
  144. return "";
  145. }
  146. long newestVersion = kvDataEntries[0].getVersion();
  147. if (newestVersion == -1) {
  148. return "";
  149. }
  150. KVDataVO[] kvDataVOS = new KVDataVO[1];
  151. long[] versions = new long[(int)newestVersion + 1];
  152. for (int i = 0; i < versions.length; i++) {
  153. versions[i] = i;
  154. }
  155. KVDataVO kvDataVO = new KVDataVO(account, versions);
  156. kvDataVOS[0] = kvDataVO;
  157. KVInfoVO kvInfoVO = new KVInfoVO(kvDataVOS);
  158. KVDataEntry[] allEntries = eventContext.getLedger().getDataEntries(ledgerHash, address, kvInfoVO);
  159. return JSON.toJSONString(allEntries);
  160. }
  161. @Override
  162. public void beforeEvent(ContractEventContext eventContext) {
  163. this.eventContext = eventContext;
  164. this.ledgerHash = eventContext.getCurrentLedgerHash();
  165. }
  166. @Override
  167. public void postEvent(ContractEventContext eventContext, Exception error) {
  168. }
  169. }
  170. ```
  171. #### 4.2、pom.xml文件实例
  172. ```xml
  173. <?xml version="1.0" encoding="UTF-8"?>
  174. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  175. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  176. <groupId>com.jd.chain</groupId>
  177. <version>1.0.0.RELEASE</version>
  178. <modelVersion>4.0.0</modelVersion>
  179. <artifactId>contract-samples</artifactId>
  180. <name>contract-samples</name>
  181. <dependencies>
  182. <dependency>
  183. <groupId>com.jd.blockchain</groupId>
  184. <artifactId>sdk-pack</artifactId>
  185. <version>1.0.0.RELEASE</version>
  186. <scope>provided</scope>
  187. </dependency>
  188. <dependency>
  189. <groupId>com.alibaba</groupId>
  190. <artifactId>fastjson</artifactId>
  191. <version>1.2.32</version>
  192. <scope>provided</scope>
  193. </dependency>
  194. </dependencies>
  195. <build>
  196. <plugins>
  197. <plugin>
  198. <groupId>com.jd.blockchain</groupId>
  199. <artifactId>contract-maven-plugin</artifactId>
  200. <version>1.0.0.RELEASE</version>
  201. <executions>
  202. <execution>
  203. <id>make-contract</id>
  204. <phase>package</phase>
  205. <goals>
  206. <goal>compile</goal>
  207. </goals>
  208. </execution>
  209. </executions>
  210. <configuration>
  211. <archive>
  212. <manifest>
  213. <mainClass>com.jd.chain.contract.TransferContractImpl</mainClass>
  214. </manifest>
  215. </archive>
  216. <finalName>contract</finalName>
  217. </configuration>
  218. </plugin>
  219. </plugins>
  220. </build>
  221. </project>
  222. ```

一个面向企业应用场景的通用区块链框架系统,能够作为企业级基础设施,为业务创新提供高效、灵活和安全的解决方案