# HOWTOs
# 1. 怎么进行调试
默认情况下,合法的合约调用会在代理节点执行,但是普通节点也可以手动打开合约虚拟机,验证区块链中的合约调用,执行合约调用。
简单的调试方法可以通过pprint输出变量,对于基本类型pprint会输出多个参数值的字符串表示, 对于函数会输出函数的内存地址,对于table类型的值会转成json字符串输出。
之后会增加远程调试功能,在远程代理节点上运行过程中断点调试。
# 2. 怎么使用event
合约中可以通过emit EventName(EventArg)抛出,EventName是自定义event名称, event名称词法要求和变量名要求一样,但是最长支持49字符, EventArg是event的参数,要求值是最长1024字符的字符串
调用合约的操作执行过程中抛出的event,会被记录到区块链中,区块链本地节点可以设置监控某合约的某event的回调脚本, 然后在区块链同步到包含被监控的event的块时,会触发设置的脚本,回调脚本也是用hvm编写。
# 3. 常见编译错误有哪些
- 变量类型和赋值不一致
- 函数调用的参数类型和实际传参类型不一致
- 函数参数类型和函数体中使用时的类型不一致,建议函数参数加上显式类型声明
- 一些代码块漏加
end
- 使用了没有申明过的变量
- 合约中定义了全局变量(合约中不允许定义新的全局变量只能读取,但是脚本中可以定义新全局变量)
- 对nil值进行一些不允许的操作符操作,比如加减乘除等
- 访问非table类型值的属性
- 其他
# 4. 对中文或者其他非英文的支持如何
变量名,函数名,event名称不可以使用中文,只能英文字符或者下划线开头,跟着若干个英文字符或者下划线或者数字, 但是字符串中的内容可以用中文或者其他语言的文字,支持unicode。
# 5. 支持多线程吗
因为hvm主要是为了在区块链的节点上运行的,考虑到区块链上的一些特性尤其是为了达成共识,不支持多线程编程
# 6. hvm中怎么使用随机数
提供两种获取随机数的方式
全局函数get_chain_random() 获取链上伪随机数,这个函数返回的随机数是可被推算出来的结果,仅用于只需要返回均匀分布的数字的地方
全局函数get_waited(blocknumber) 可以获取根据指定块的块号上的二进制内容产生的一个int32数字,参数可以是过去块也可以是未来块的块号要用这种方式获取随机数,可以调用全局函数get_header_block_num()获取到前一个块的块号, 然后用未来的某个块号(当前块号加上未来块的数量,大概10秒一个块)作为参数调用get_waited函数,如果执行的时候当前区块链还没有到这个块号,返回-1, 如果执行的时候当前区块链已经超过了这个块号,返回根据那个块上数据产生的一个int32数字。以彩票为例,设置get_waited的参数为预计开奖时间的未来块号, 然后在开奖前一段时间前允许投注,这时候get_waited参数的块号还没有到这个块,返回类型是-1,所有人都不知道到开奖时间后这个函数调用的返回结果会是多少。 当开始时间到了后,调用get_waited的返回结果固定下来一个int32类型的正数,并且以后任何节点每次用同一个参数调用结果都是固定的,随机数被确定下来了。 可以根据需要用这个返回值 (result % 10000) / 10000 来得到[0, 1)之间的精度4位小数的随机数
# 7. 怎么实现面向对象的类型继承和多态
可以使用table类型和record类型模拟对象,record类型有默认属性值,并且属性可以是有默认实现的函数
比如
type Person = {
id: string default "123",
name: string default "hvm",
age ?: int = 24, -- record属性默认值既可以用default也可以用=区分
fn: (number, number) => number default
function (a: number, b: number)
return a + b
end
}
let p = Person()
pprint(p.id, p.name, p.age)
let n = p.fn(p.age, 2016)
pprint(n)
如果需要实现类似面向对象语言中的类型继承和多态功能的话,可以实现一个extend函数,调用子record类型的构造函数后,用extend函数 接受子对象和父类型,在extend函数中创建新的父类型的对象,然后给把父类型对象中子类型对象没有的属性赋值给子类型对象。用这种 方法可以起到继承和多态的效果。目前没有给出标准的extend函数,给出一个示例实现
let function extend(obj, parent_class)
let parent = parent_class(obj)
for k, v in pairs(parent) do
obj[k] = v
return totable(obj)
end
type A = {
name1: string,
age1: int default 100
}
type B = {
name: string,
age: int
}
let b = B()
extend(b, A)
-- or
let c = extend(B(), A)
还有一种实现类型继承和多态的方法是使用setmetatable和元表,这以后会给出更多文档和例子