合约简介
HVM智能合约简介
HVM智能合约,是指运行在HVM执行环境当中的Java语言编写的智能合约。具有易编写,易运维,高效灵活的特点,目前是Hyperchain平台推荐的智能合约方案,目前HVM智能合约还处在活跃的开发测试阶段。
合约结构
一份HVM智能合约包括以下部分组成:
- 合约主体类(ContractMainClass)
- 合约可见接口 (ContractVisableInterface)
- 合约调用类 (ContractInvokeBean)*
- 合约功能Bean (ContractDTO)
* 说明: 合约调用类并不需要部署到区块链上
合约主体类
就像Java程序的执行都会有一个入口的Main方法一样,HVM智能合约也需要指定一个合约主体类。 合约可以有多个类,但必须有一个主体类,执行环境会解析主体类中的方法逻辑,用户可以自行调用主体类中的方法。
在主类中,可以实现多个钩子方法在合约执行的各个阶段执行需要的逻辑。同时,合约可以实现多个用户自定义的合约方法接口,不同的接口可以包含不同的方法给调用者调用。
因此,一份HVM合约是指包含主体类以及主体类需要的类的集合。
以下是合约主体类的一个简单示例:
public class DemoContract extends BaseContract implements IDemoA, IDemoB {
@StoreField
public String name; // 持久化属性
public int version; // 非持久化属性
public DemoContract() {} // 无参构造方法
@Override
public Boolean foo(String arg1, int arg2) {/*...*/}
@Override
public String bar(MyObject arg1, boolean arg2) {/*...*/}
@Override
public void onInit() {/*...*/}
@Override
public void onCommitted() {/*...*/}
}
合约可见接口
合约主体类需要实现合约可见接口,合约可见接口是指继承了BaseContractInterface
的接口,而BaseContractInterface
是一个空接口,用户仅可以调用可见接口中所声明的方法。
合约调用用户只需要在应用中得到可见接口即可,不需要得到合约代码的实现。这也比较适合合约开发团队和应用开发团队不是一个团队,或者是合约开发者希望只交付接口的场景。
用户可以通过开放不同可见范围的接口,实现逻辑层面的权限控制。
以可见接口IDemoA
和可见接口IDemoB
为例,其实现的代码如下:
- IDemoA 部分可见
public interface IDemoA extends BaseContractInterface{
Boolean foo(String k, int v);
}
- IDemoB 完全可见
public interface IDemoB extends BaseContractInterface{
Boolean foo(String k, int v);
String bar(MyObject k, boolean v);
}
合约调用类 (InvokeBean)
合约调用类也称为InvokeBean
,尽管其往往不包括在智能合约包当中,但是是智能合约调用过程当中不可或缺的部分。
目前HVM的智能合约是不需要进行参数转换和编码的,这需要归功于InvokeBean,因为所有的参数都是通过InvokeBean进行处理后传输给执行引擎的。
InvokeBean
也被视为是带逻辑的DTO,它将合约的部分逻辑由客户端传输给执行引擎,完成最终的逻辑组装。InvokeBean
代码需要由应用完成,通过Hyperchain JavaSDK实现智能合约方法的调用。
以下是一个简单的InvokeBean
调用类的示例:
public class InvokeGetData implements BaseInvoke<Boolean, IDemoA> {
String k;
int v;
public InvokeGetData(){}; /* 必须包括无参构造函数 */
public InvokeGetData(String k, int v){
this.k = k;
this.v = v;
}
@Override public Boolean invoke(IDemoA demoA) {
return demoA.foo(this.k, this.v);
}
}
合约功能Bean
在合约调用过程当中可能需要传输一些用户自定义的数据类型,我们称为是功能Bean,该类数据类型需要在链上和用户应用均有定义,可以认为是一种DTO,主要用途是实现数据协议匹配。
如在IDemoB
中bar
方法的第一个参数MyObject
就是一个功能Bean,其需要在合约当中定义,也需要在InvokeBean
能够引用到的应用包内定义,需要注意应用以及链上DTO类的全限定名应当是一致的。
public interface IDemoB extends BaseContractInterface{
Boolean foo(String k, int v);
String bar(MyObject /* DTO 类*/ k, boolean v);
}
下面是一个简单的DTO类的示例:
public class MyObject{
public String data1;
public int data2;
public class MyObject(){}
public int hashcode() {/* 省略 */}
public boolean equals(Object obj){/* 省略 */}
}
持久化属性
HVM为了区分需要永久存储在区块链上的合约属性和临时使用的合约属性,引入了持久化属性的概念。持久化属性是指将会存储在区块链的世界状态中的属性。而临时属性是指仅会在执行过程当中生效,并不会在是饥饿状态中进行存储的属性。
HVM在环境中引入了一个全新的注解@StoreField
,该注解的生效范围是运行时属性生效,使用该注解标记的类属性将被执行环境认为是持久化属性。
public class DemoContract extends BaseContract implements IDemoA, IDemoB {
@StoreField
public String name; // 持久化属性
public int version; // 非持久化属性
/* 省略其他部分 */
}
执行性能
目前针对HVM进行了一些简单的性能测试,场景主要是纯计算逻辑,不同的环境执行结果不同,仅供参考。
斐波那契数组计算 (ms)
针对求解不同长度n的斐波那契数列的计算结果(递归计算)。
执行环境 | n = 10 | n = 20 | n = 30 | n = 40 |
---|---|---|---|---|
HVM | 6 | 7 | 190 | 20950 |
EVM | 42 | 63 | 2908 | 155550 |
HotSpot | 110 | 110 | 110 | 450 |
life(WASM) | 0.590 | 2.67 | 247.3 | 29422 |
冒泡排序 (ms)
针对求解不同长度L的数组的冒泡排序所消耗时间结果。
执行环境 | L = 10 | L = 100 | L = 1000 | L = 10000 |
---|---|---|---|---|
HVM | 1(20) | 1(20) | 76(80) | 6941(7750) |
EVM | 40 | 90 | 4962 | 443520 |
HotSpot | 1(110) | 1(110) | 8(120) | 276(410) |
归并排序 (ms)
针对求解不同长度L的数组的归并排序所消耗时间结果。
执行环境 | L = 10 | L = 100 | L = 1000 | L = 10000 |
---|---|---|---|---|
HVM | 1(20) | 1(20) | 3(20) | 31(1490) |
EVM | 55 | 60 | 220 | 240 |
HotSpot | 1(110) | 1(110) | 2(110) | 7(190) |