函数¶
用户自定义函数¶
sCrypt允许开发者定义自己的函数,如下所示:
function sum(int a, int b): int {
return a + b;
}
这些函数只在合约内可见,类似于 Solidity 中的 private
函数。
公共函数¶
如果公共函数运行完成,则返回 true
,否则返回 `false
。它没有返回类型和 返回
部分,返回语句是是隐式包含的。换句话说,
public function isZero(int a) {
require(a == 0);
}
在功能上等同于
public function isZero(int a): bool {
require(a == 0);
return true;
}
静态函数和静态属性¶
可以通过合约名来直接引用静态函数/方法,而不必创建合约实例。类似于 Javascript 或 C++ 中的静态函数/属性。在定义它的合约中,静态属性/函数也可以在没有合约前缀的情况下被引用。
library Foo {
static int N = 0;
static function incByN(int a): int {
// N is used with and without Foo prefix
return a + Foo.N + N;
}
static function double(int x): int {
// incByN() is called with prefix and without
return Foo.incByN(x) + incByN(x);
}
}
contract Bar {
public function unlock(int y) {
require(y == Foo.double(2));
require(y == Foo.N);
// N cannot be referenced without Foo prefix
// require(y == N);
}
}
return
语句¶
由于比特币脚本缺乏对 return
语义的支持,所以函数必须以 return
语句结尾,并且 return
语句只能放在函数末尾,不能放在其他位置。将来可能会放松这个限制。一般来说这不是问题,可以用如下方式避免在其他位置返回:
function abs(int a): int {
if (a > 0) {
return a;
} else {
return -a;
}
}
可以改写为
function abs(int a): int {
int ret = 0;
if (a > 0) {
ret = a;
} else {
ret = -a;
}
return ret;
}
递归¶
不允许递归。函数不能直接或间接地在其主体中调用自身。
库函数¶
sCrypt实现了如下库函数,在全局可见。
数学¶
int abs(int a)
int min(int a, int b)
int max(int a, int b)
bool within(int x, int min, int max)
哈希¶
Ripemd160 ripemd160(bytes b)
Sha1 sha1(bytes b)
Sha256 sha256(bytes b)
Ripemd160 hash160(bytes b)
ripemd160(sha256(b))
Sha256 hash256(bytes b)
sha256(sha256(b))
Sha256 flattenSha256(T a)
为任何类型的给定参数 a 返回 Sha256。如果
T
是基本类型,如bool / int / bytes
,则返回与sha256(a)
相同。如果T
是复合类型(即数组和结构体),它将 a 的每个展平字段的所有 sha256 值连接起来形成一个联合字节,然后对其调用sha256
以获得最终的结果。
签名验证¶
bool checkSig(Sig sig, PubKey pk)
如果签名与公钥匹配,则返回 true。如果签名是空字节数组,则返回 false。否则,由于 NULLFAIL 规则,整个合约立即失败。
bool checkMultiSig(Sig[M] sigs, PubKey[N] pks)
如果有且仅有 M 个签名与 N 个公钥中的 M 个匹配,则返回 true。 M 和 N 可以是任意数字,只要 M <= N。如果所有签名都是空字节数组,则返回 false。否则,整个合约立即失效。
bytes
操作¶
- 与
int
之间的转换
bytes
可以使用函数 unpack
转换为 int
。使用采用小端格式的 符号-值 表示法,其中最高有效位表示符号( 0
表示正, 1
表示负)。 int
可以使用 pack
转换为 bytes
。
int a1 = unpack(b'36'); // 54 decimal int a2 = unpack(b'b6'); // -54 int a3 = unpack(b'e803'); // 1000 int a4 = unpack(b'e883'); // -1000 bytes b = pack(a4); // b'e883'
bytes num2bin(int num, int size)
把数字
num
转换为字节数为size
的字节数组,包括符号比特。如果字节数组无法容纳被转换的数字,则会转换失败。len()
返回长度。int a = len(b'ffee11'); // a == 3
切片操作符 -
b[start:end]
返回b
的子数组,从索引start
(包含)到end
(不包含)。start
如果省略则为0
,end
如果省略则为数组的长度。bytes b = b'0011223344556677'; // b[3:6] == b'334455' // b[:4] == b'00112233' // b[5:] = b'556677'
拼接
bytes b = b'00112233' + b'334455' // b == b'00112233334455'
reverseBytes(bytes b, static const int size)
返回
b
的反向字节,size
是b
字节的大小。注意size
必须是 编译时常量 。在小端和 大端之间转换数字时,它通常很有用。// returns b'6cfeea2d7a1d51249f0624ee98151bfa259d095642e253d8e2dce1e79df33f79' reverseBytes(b'793ff39de7e1dce2d853e24256099d25fa1b1598ee24069f24511d7a2deafe6c', 32)