长安链Docker Java智能合约引擎的架构、应用与规划

2024-03-20 07:44

本文主要是介绍长安链Docker Java智能合约引擎的架构、应用与规划,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

#功能发布

长安链3.0正式版发布了多个重点功能,包括共识算法切换、支持java智能合约引擎、支持后量子密码、web3生态兼容等。我们接下来为大家详细介绍新功能的设计、应用与规划。

在《2022年度长安链开源社区开发者调研报告》中,对Java合约语言支持是开发者更为普遍的需求;《2023年中国开发者调研报告》显示,熟悉Java语言的开发者占到40%以上,尤其在传统行业应用中为应对使用区块链技术进行数字化转型的需求,支持java语言合约将使区块链技术更快的渗透到各行各业。

Docker Go上线以来,因其良好的可移植性,可扩展性和安全性获得较多使用,更因其支持使用原生的Go语言编写合约,有更好的易用性。

在企业客户的使用中Java语言的使用更为广泛,因此在长安链v3.0.0正式版中新增Docker Java合约引擎,支持使用原生Java语言编写合约。

 1. 整体架构 

Docker Java合约引擎的设计复用了Docker Go的架构。依然是采用抢占式任务调度和多个合约进程并发,单个合约进程串行执行交易的形式运行。更详细的设计可以参考长安链 VM Engine架构设计深度解读。

Docker Java 和 Docker Go 合约引擎互不冲突,可以同时启用。部署和连接方式如下图所示:

图片

 2. 编写Java合约 

2.1 版本和工具

当前合约执行环境为JDK 11,推荐使用JDK 11编写合约;推荐使用 IDEA 或 Vscode等IDE编写和编译Java合约。

2.2 引用合约sdk

2.2.1 添加依赖包
在gradle项目中使用SDK

在build.gradle 中添加dependencies:

implementation group:'org.chainmaker', name:'contracts-sdk-java', version:'1.0'

在Maven项目中使用SDK

在pom.xml 中添加dependencies:

<dependency>

    <groupId>org.chainmaker</groupId>

    <artifactId>contracts-sdk-java</artifactId>

    <version>1.0</version>

</dependency>

2.2.2 本地编译包

将项目引入到本地并编译安装到本地maven库:

git clone -b v3.0.0 https://git.chainmaker.org.cn/chainmaker/contract-sdk-java.git

cd contract-sdk-javamvn clean install  

'-Dmaven.test.skip=true'

然后通过添加依赖包引入到合约开发项目。

2.3 合约编写规则 

2.3.1 合约必须实现接口 IContract

合约必须需要实现合约初始化方法(initContract) 和合约升级方法(upgradeContract)。

IContract 中定义了默认的 initContract 和 upgradeContract 的接口。默认这两个接口只返回成功的message。

合约可以根据需求自行实现这两个接口。

2.3.2 代码的执行入口

在合约类定义的main方法中,需要将合约实例作为参数传给sanbox.serve:

publicclass fact implementsIContract{

    // ... 

   publicstaticvoidmain(String[] args){

        Sandbox.serve(args,newfact());

    }

}

2.3.3 定义合约方法

在合约类中定义合约方法,方法权限必须是public,返回值为Response,并且使用@ContractMethod注解标识。在链上调用中,指定的合约方法名与定义的方法名同名(区分大小写):

 @ContractMethod

    publicResponsesave()throwsIOException,

ContractException{

SDK.putState("key1","field1", 

SDK.getParam("value"));

        return SDK.success("store success");

   }

2.3.4 获取合约的调用参数

(1)使用SDK.getArgs()获取参数map

// 获取参数map

Map<String, ByteString> args = SDK.getArgs();

// 获取参数 key的值, 如果不存在则报错

ByteString getKey = args.get("key");

if(getKey ==null){

   return SDK.error("key not exist");

}

String key = getKey.toStringUtf8();

// 获取参数 value 的值, 如果不存在使用空字符串

ByteString getField = args.get("field");

String field = getField ==null?"": getField.toStringUtf8();

(2)使用SDK.getParam() 和 SDK.getParamBytes()

注意:getParam 和 getParamBytes 不做null值的判断,假如参数值没有传递,则分别返回空字符串和空字节数组:

String key = SDK.getParam("key");

byte[] value = SDK.getParamBytes("value");

2.3.5 错误捕获

合约报错中ContractException中包含了正常逻辑的报错,主要包括参数的合法性检查(比如key 和field),和链上接口访问遇到的报错(比如访问的value不存在等)。因此在合约逻辑中,建议捕获ContractException,并在合约里做相应的处理。

2.4 合约编译

合约需要编译成可独立运行的jar包(包含运行所需的依赖,也叫fat jar 或uber jar)。由于包含了所有依赖,因此合约体积也较大,大概30MB左右。

2.4.1 gradle 打包方式

配置示例如下,执行./gradlew uberJar,默认生成的jar包在build/libs目录下,文件名以-uber.jar为结尾。

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-shade-plugin</artifactId>

    <version>3.4.0</version>

    <executions>

        <execution>

            <phase>package</phase>

            <goals>

                <goal>shade</goal>

            </goals>

            <configuration>

                <filters>

                    <filter>

                        <artifact>*:*</artifact>

                        <excludes>

                            <exclude>META-INF/*.SF</exclude>

                            <exclude>META-INF/*.DSA</exclude>

                            <exclude>META-INF/*.RSA</exclude>

                        </excludes>

                    </filter>

                </filters>

                <transformers>

                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>

                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                        

                      <mainClass>org.chainmaker.examples.demo</mainClass>

                    </transformer>

                </transformers>

            </configuration>

        </execution>

    </executions>

</plugin>

2.4.2 maven 打包方式

使用maven-shade-plugin。配置示例如下。

执行 mvn package,默认生成的jar包在target目录下:

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-shade-plugin</artifactId>

    <version>3.4.0</version>

    <executions>

        <execution>

            <phase>package</phase>

            <goals>

                <goal>shade</goal>

            </goals>

            <configuration>

                <filters>

                    <filter>

                        <artifact>*:*</artifact>

                        <excludes>

                            <exclude>META-INF/*.SF</exclude>

                            <exclude>META-INF/*.DSA</exclude>

                            <exclude>META-INF/*.RSA</exclude>

                        </excludes>

                    </filter>

                </filters>

                <transformers> 

                  <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>

                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">

                        

                      <mainClass>org.chainmaker.examples.demo</mainClass>

                    </transformer>

                </transformers>

            </configuration>

        </execution>

    </executions>

</plugin>

示例合约 

示例合约可以直接查看仓库的样例contracts-sdk-java(链接地址:https://git.chainmaker.org.cn/chainmaker/contract-sdk-java/-/tree/v3.0.0/src/main/java/org/chainmaker/examples)。

一个完整的简单存证合约可以如下:

packageorg.chainmaker.examples;

importcom.google.protobuf.ByteString;

importorg.chainmaker.contracts.docker.java.pb.proto.Response;

importorg.chainmaker.contracts.docker.java.sandbox.IContract;

importorg.chainmaker.contracts.docker.java.sandbox.ContractException;

importorg.chainmaker.contracts.docker.java.sandbox.SDK;

importorg.chainmaker.contracts.docker.java.sandbox.Sandbox;

importorg.chainmaker.contracts.docker.java.sandbox.annotaion.ContractMethod;

importjava.io.IOException;

// 实现智能合约接口 IContract

publicclass fact implementsIContract{

   // 使用@ContractMethod注解定义合约方法:save

   @ContractMethod

   publicResponsesave()throwsIOException,ContractException{

       // 获取参数:key

       String key = SDK.getParam("key");

       // 获取参数:value

       byte[] value = SDK.getParamBytes("value");

       // 将键值对存储到链上

        SDK.putState(key, value);

       // 返回成功信息

       return SDK.success("store success");

   }

   // 定义合约方法:get

   @ContractMethod

   publicResponseget()throwsIOException,InterruptedException,ContractException{

       // 获取参数:key

       String key = SDK.getParam("key");

       // 从链上获取对应的值并返回

       return SDK.success(SDK.getState(key));

   }

   // 主函数,启动智能合约

   publicstaticvoidmain(String[] args){

       Sandbox.serve(args,newfact());

   }

}

 接口支持 

目前提供了与Docker Go接口功能一致的所有接口。但是为了遵循Java语言的风格,与Docker Go接口略有不同:

1. 支持函数重载,因此没有Go接口中略显冗余的GetState,GetStateByte,GetStateFromKey,GetStateFromKeyByte等接口,而是函数名统一使用getState。

2. 2. 函数名首字母使用小写。

具体接口列表可以查看文档链接:https://docs.chainmaker.org.cn/v3.0.0/html/instructions/%E4%BD%BF%E7%94%A8Java%E8%BF%9B%E8%A1%8C%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6%E5%BC%80%E5%8F%91.html#id15

 下一步规划 

目前对于Docker Java下一步的主要规划是:

1. 优化合约创建效率。因Docker Java的合约体积较大,未来会选择支持源码安装的合约创建方案,以降低创建合约对其他交易产生的性能影响;

2. 优化Docker Java交易执行效率。因JVM的启动相对较慢,以进程方式做调度对Docker Java的交易执行效率影响较大。

如果您对Docker Java有更多建议,欢迎提交issue或在社群联系我们。

这篇关于长安链Docker Java智能合约引擎的架构、应用与规划的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/828761

相关文章

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

Java 字符数组转字符串的常用方法

《Java字符数组转字符串的常用方法》文章总结了在Java中将字符数组转换为字符串的几种常用方法,包括使用String构造函数、String.valueOf()方法、StringBuilder以及A... 目录1. 使用String构造函数1.1 基本转换方法1.2 注意事项2. 使用String.valu

java脚本使用不同版本jdk的说明介绍

《java脚本使用不同版本jdk的说明介绍》本文介绍了在Java中执行JavaScript脚本的几种方式,包括使用ScriptEngine、Nashorn和GraalVM,ScriptEngine适用... 目录Java脚本使用不同版本jdk的说明1.使用ScriptEngine执行javascript2.

Spring MVC如何设置响应

《SpringMVC如何设置响应》本文介绍了如何在Spring框架中设置响应,并通过不同的注解返回静态页面、HTML片段和JSON数据,此外,还讲解了如何设置响应的状态码和Header... 目录1. 返回静态页面1.1 Spring 默认扫描路径1.2 @RestController2. 返回 html2

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

Java操作ElasticSearch的实例详解

《Java操作ElasticSearch的实例详解》Elasticsearch是一个分布式的搜索和分析引擎,广泛用于全文搜索、日志分析等场景,本文将介绍如何在Java应用中使用Elastics... 目录简介环境准备1. 安装 Elasticsearch2. 添加依赖连接 Elasticsearch1. 创

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、

SpringBoot 整合 Grizzly的过程

《SpringBoot整合Grizzly的过程》Grizzly是一个高性能的、异步的、非阻塞的HTTP服务器框架,它可以与SpringBoot一起提供比传统的Tomcat或Jet... 目录为什么选择 Grizzly?Spring Boot + Grizzly 整合的优势添加依赖自定义 Grizzly 作为