语法规范¶
形式规范¶
大部分语法含义都是显而易见的。sCrypt特有的语法会在后面介绍。
行注释以 //
开头,块注释位于 /*
和 */
之间。
类型¶
基本类型¶
bool - 布尔值
true
或false
。int - 任意长度的有符号整数,字面量(literals)有十进制和十六进制两种格式。
int a1 = 42; int a2 = -4242424242424242; int a3 = 55066263022277343669578718895168534326250603453777594175500187360389116729240; int a4 = 0xFF8C;
bytes - 一个可变长度的字节数组,其字面量是带引号的十六进制格式,前缀为
b
,或双引号 UTF8 字符串。bytes b1 = b'ffee1234'; bytes b2 = b'414136d08c5ed2bf3ba048afe6dcaebafeffffffffffffffffffffffffffffff00'; bytes b3 = b'1122' + b'eeff'; // b3 is b'1122eeff' bytes str = "hello world"; // utf8 string
数组类型¶
数组是长度固定的,具有相同基本类型的值列表。
数组常量 - 以逗号分隔的表达式列表,括在方括号中。数组大小必须是大于零的整数常量。
bool[3] b = [false, false && true || false, true || (1 > 2)]; int[3] c = [72, -4 - 1 - 40, 833 * (99 + 9901) + 8888]; bytes[3] a = [b'ffee', b'11', b'22']; int[2][3] d = [[11, 12, 13], [21, 22, 23]]; // array demension can be omitted when declared int[] e = [1, 4, 2]; // e is of type int[3] int[][] f = [[11, 12, 13], [21, 22, 23]]; // f is of type int[2][3]
将数组初始化/设置为相同值 - 函数
T[size] repeat(T e, static const int size)
返回一个数组,其中所有size
元素都设置为e
,其中T
可以是任何类型。注意size
必须是 编译时常量。// a == [0, 0, 0] int[3] a = repeat(0, 3); // arr2D == [[0, 0, 0], [0, 0, 0]] int[2][3] arr2D = repeat(a, 2); int[4] flags = [false, true, false, true] // set all flags to be false flags = repeat(false, 4);
索引运算符 - 索引从
0
开始。越界访问立即使合约执行失败。int[3] a = [1, 4, 2]; int[2][3] arr2D = [[11, 12, 13], [21, 22, 23]]; int d = a[2]; a[1] = -4; int idx = 2; // read d = a[idx]; d = arr2D[idx][1]; // write a[idx] = 2; // assign to an array variable a = arr2D[1]; // b is a new copy and the same as a int[3] b = a; // two arrays are equal if and only if they are of the same size and all elements are equal require(a == b);
结构体¶
结构体是单个名称下的变量的集合。变量可以是不同的基本类型、数组或结构体
定义结构体
struct Point { int x; int y; } struct Line { // nested struct Point start; Point end; }
- 使用结构体
Point p = {10, -10}; int x = p.x; p.y = 20; // Define a variable q of type Point, and set members to the same values as those of p Point q = p; require(p == q); // true // nested Line l = {p, q}; l.start.x = l.end.y + 1;
类型推断¶
auto
关键字表示变量的类型由变量的初始值自动推导出来。
auto a1 = b'36'; // bytes a1 = b'36'; auto a2 = 1 + 5 * 3; // int a2 = 1 + 5 * 3;
类型别名¶
类型别名为类型创建一个新名称。它实际上并没有创建一个新类型,它只是创建一个新名称来引用该类型。请注意,声明的右侧不能是未指定的泛型结构类型。
type Age = int; type Coordinate = int[2]; type A = ST<int>; // this is fine. type B = ST; // this is not allowd.
泛型/泛型类型¶
泛型类型是参数化类型。它允许库/结构体处理多种类型而不是单一类型。用户可以创建这些库/结构体并使用他们自己的具体类型。
- 声明泛型类型
泛型类型可以在库级别声明并在库的范围内使用,也可以在结构级别声明并在内部使用。
// declare a library with two generic type variables: K & V library HashedMap<K, V> { // use them as function parameters' type function set(K k, V v, int idx) { ... } } // declare a struct with two generic type variables: T & P struct ST<T, P> { T x; P y; }
实例化泛型类型
// initialize a library with generics HashedMap<bytes, int> map = new HashedMap(); // initialize a struct with generics ST<int, bytes> st = {1, b'02'};
子类型¶
有几个特定于比特币上下文的子类型,用于进一步提高类型安全性。
bytes
的子类型¶
要把 bytes
类型强制转换成某个子类型,必须显式调用与该子类型同名的函数。
PubKey - 一种公钥类型。
PubKey pubKey = PubKey(b'0200112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100');
Sig - DER 格式的签名类型。包含 签名哈希类型,如下例子中的签名哈希类型是
SIGHASH_ALL | SIGHASH_FORKID
(0x41
) 。Sig sig = Sig(b'3045022100b71be3f1dc001e0a1ad65ed84e7a5a0bfe48325f2146ca1d677cf15e96e8b80302206d74605e8234eae3d4980fcd7b2fdc1c5b9374f0ce71dea38707fccdbd28cf7e41');
Ripemd160 - RIPEMD-160 哈希类型。
Ripemd160 r = Ripemd160(b'0011223344556677889999887766554433221100');
PubKeyHash - Ripemd160 类型的别名。通常代表一个比特币地址。
PubKeyHash aliceAddress = PubKeyHash(b'0011223344556677889999887766554433221100');
Sha1 - SHA-1 哈希类型。
Sha1 s = Sha1(b'0011223344556677889999887766554433221100');
Sha256 - SHA-256 哈希类型。
Sha256 s = Sha256(b'00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100');
SigHashType - 签名哈希类型。
SigHashType s = SigHashType(b'01'); SigHashType s = SigHash.ALL | SigHash.ANYONECANPAY;
SigHashPreimage - sighash 原像类型。
SigHashPreimage s = SigHashPreimage(b'0100000028bcef7e73248aa273db19d73');
OpCodeType - 操作码类型。
OpCodeType s = OpCode.OP_DUP + OpCode.OP_ADD;
int
的子类型¶
PrivKey - 私钥类型。
PrivKey privKey = PrivKey(0x00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100);
const
变量¶
声明为 const
的变量一旦初始化就不能更改。
contract Test {
const int x;
constructor(int x) {
this.x = x; // good, since this is initialization
}
public function equal(const int y) {
y = 1; // <-- error
const int a = 36;
a = 11; // <-- error
require(y == this.x);
}
}
if
语句¶
if
条件可以是 int
和 bytes
类型,除了 bool
。它们像在 C 和 Javascript 中一样被隐式转换为 bool
。 int
表达式被评估为 false
当且仅当它为 0
(包括负数 0
)。 bytes
表达式被评估为 false
当且仅当它的每个字节都是 b'00'
(包括空的 bytes
b''
)。
int cond = 25; // true int cond = 0; // false int cond = unpack(b'80') // false since it is negative 0 int cond = unpack(b'000080') // false since it is negative 0 if (cond) {} // equivalent to if (cond != 0) {} bytes cond = b'00'; // false bytes cond = b''; // false bytes cond = b'80'; // true. Note b'80' is treated as false if converted to int bytes cond = b'10' & b'73'; // true since it evaluates to b'10' if (cond) {}
exit()
语句¶
exit(bool status);
语句终止合约执行。如果 status
为 true
,则合约执行成功;否则合约执行失败。
contract TestPositiveEqual { int x; constructor(int x) { this.x = x; } public function equal(int y) { if (y <= 0) { exit(true); } require(y == this.x); } }
Code Separator 代码分隔符¶
Three or more *
in a line inserts an OP_CODESEPARATOR. It is used to exclude what comes before it (including itself), from being part of the signature.
Note there is no ;
at the end.
contract P2PKH_OCS { Ripemd160 pubKeyHash; public function unlock(Sig sig, PubKey pubKey) { // code separator 1 *** require(hash160(pubKey) == this.pubKeyHash); // code separator 2 ***** require(checkSig(sig, pubKey)); } }
访问修饰符¶
可以使用三种类型的访问修饰符来帮助限制合约的属性和函数的范围:
- 默认:不需要关键字
- 私有的
- 公共:仅适用于函数
比特币交易只能从外部调用公共函数。
default | private | public | |
---|---|---|---|
合约内 | Yes | Yes | Yes |
其他合约 | Yes | No | Yes |
外部 | No | No | Yes |
运算符¶
优先级 | 运算符 | 关联性 | 注意 |
---|---|---|---|
1 | () ++ -- . |
左 | |
2 | [] |
左 | |
3 | ++ -- - ! ~ |
右 | |
4 | * / % |
左 | |
5 | + - |
左 | |
6 | << >> |
左 | 要移位的位数必须为非负数,否则立即失败 |
7 | < <= > >= |
左 | |
8 | == != |
左 | |
9 | & |
左 | 在两个长度不同的整数的情况下,较短的首先使用 num2bin 扩展为与较长的相同的长度 |
10 | ^ |
左 | 与 & 相同 |
11 | | |
左 | 与 & 相同 |
12 | && |
左 | |
13 | || |
左 | |
14 | ? : |
右 | |
15 | += -= *= /= %= &= |= ^= <<= >>= |
右 |
作用域¶
sCrypt的作用域遵循C99和Solidity的现行作用域规则。外部作用域的变量会被内部作用域的同名变量覆盖。