语法规范

形式规范

\[\begin{split}\begin{align*} program &::= [importDirective]^*\ [contract]^+\\ importDirective &::= \mathrm{import}\ "\mathrm{ID}";\\ contract &::= \mathrm{contract}\ \mathrm{ID}\ \{\ [var]^*\ [constructor]\ [function]^+\ \}\\ var &::= formal;\\ formal &::= \mathrm{TYPE}\ \mathrm{ID}\\ constructor &::= \mathrm{constructor}([formal[,\ formal]^*])\ \{\ [stmt]^*\ \}\\ function &::= \mathrm{[public|static]}\ \mathrm{function}\ \mathrm{ID}([formal[,\ formal]^*])\ \mathrm{[returns}\ (\mathrm{TYPE]})\ \{\ [stmt]^*\ \mathrm{[return}\ expr;]\ \}\\ stmt &::= \mathrm{TYPE}\ \mathrm{ID} = expr;\\ &\ \ \ |\ \ \mathrm{ID}\ \mathrm{ID} = \mathrm{new}\ \mathrm{ID}(expr^*);\\ &\ \ \ |\ \ \mathrm{ID} = expr;\\ &\ \ \ |\ \ \mathrm{require}(expr);\\ &\ \ \ |\ \ \mathrm{exit}(expr);\\ &\ \ \ |\ \ \mathrm{if}\ (expr)\ stmt\ [\mathrm{else}\ stmt]\\ &\ \ \ |\ \ \mathrm{loop}\ (intConst)\ stmt\\ &\ \ \ |\ \ \{\ [stmt]^*\ \}\\ &\ \ \ |\ \ \mathrm{CODESEPARATOR}\\ expr &::= \mathsf{UnaryOp}\ expr\\ &\ \ \ |\ \ expr\ \mathsf{BinaryOp}\ expr\\ &\ \ \ |\ \ \mathrm{ID}(expr[,\ expr]^*)\\ &\ \ \ |\ \ \mathrm{ID}.\mathrm{ID}\\ &\ \ \ |\ \ \mathrm{ID}.\mathrm{ID}(expr[,\ expr]^*)\\ &\ \ \ |\ \ \mathrm{ID}\mathbf{[}expr:expr\mathbf{]}\\ &\ \ \ |\ \ (expr)\\ &\ \ \ |\ \ \mathrm{ID}\\ &\ \ \ |\ \ boolConst \\ &\ \ \ |\ \ intConst \\ &\ \ \ |\ \ bytesConst \\ \end{align*}\end{split}\]

大部分语法含义都是显而易见的。sCrypt特有的语法会在后面介绍。

行注释用 // 开头,在 /**/ 之间的是块注释。

类型

基本类型

  • bool - 布尔类型,值为 truefalse

  • int - 有符号的任意长度整数类型,字面量(literals)有十进制和十六进制两种格式。

    int a1 = 42;
    int a2 = -4242424242424242;
    int a3 = 55066263022277343669578718895168534326250603453777594175500187360389116729240;
    int a4 = 0xFF8C;
    
  • bytes - a variable length array of bytes, whose literals are in quoted hexadecimal format prefixed by b.

    bytes b1 = b'ffee1234';
    bytes b2 = b'414136d08c5ed2bf3ba048afe6dcaebafeffffffffffffffffffffffffffffff00';
    bytes b3 = b'1122' + b'eeff'; // b3 is b'1122eeff'
    

数组类型

An array is a fixed-size list of values of the same basic type.

  • Array Literals - a comma-separated list of expressions, enclosed in square brackets. Array size must be an integer constant greater than zero.

    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]
    
  • Initialize/set an array to the same value - Function T[size] repeat(T e, static const int size) returns an array with all size elements set to e, where T can be any type. Note size must be a compile time constant.

    // a == [0, 0, 0]
    int[3] a = repeat(0, 3);
    // arr2D == [[0, 0, 0], [0, 0, 0]]
    int[2][3] arr2D = repeat(0, 2);
    int[4] flags = [false, true, false, true]
    // set all flags to be false
    flags = repeat(false, 4);
    
  • Index Operator - index starting from 0. Out of bound access fails contract execution immediately.

    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;
    // variable index is allowed when reading an array
    d = a[idx];
    d = arr2D[idx][1];
    // variable index is disallowed when writing into an array
    a[idx] = 2;
    // only a compile-time constant (CTC) can be used as an index when writing
    a[2] = 2;
    a[N] = 3; // N is a CTC
    // 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 Types

A struct (or structure) is a collection of variables (can be of different basic types) under a single name.

  • Define Struct

    struct Point {
      int x;
      int y;
    }
    
    struct Line {
      // nested struct
      Point start;
      Point end;
    }
    
  • Use Struct
    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 Aliases

Type aliases create a new name for a type. It does not actually create a new type, it merely creates a new name to refer to that type.

type Age = int;
type Coordinate = int[2];

领域子类型

如下是一些在比特币语境中特定的子类型,用于进一步提高类型安全性。

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');
    
  • 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 - 签名哈希原像类型(a sighash preimage type)。

    SigHashPreimage s = SigHashPreimage(b'0100000028bcef7e73248aa273db19d73');
    
  • OpCodeType - 操作码类型

    OpCodeType s = OpCode.OP_DUP + OpCode.OP_ADD;
    

int 的子类型

  • PrivKey - 私钥类型

    PrivKey privKey = PrivKey(0x00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100);
    

const Variables

Variables declared const cannot be changed once initialized.

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 语句

除了 bool 类型, if 条件还可以是 intbytes 。这些类型会被隐式转换为 bool 类型,与 C 和 Javascript 语言中的处理方式一样。当且仅当 int0 (包括负 0 )时,为 false 。当且仅当 bytes 的每个字节都是 b'00' (包括空 bytes b'' )时,为 false

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);
    }
}

代码分隔符

一行中三个或更多 * 表示插入一个 OP_CODESEPARATOR 。 该操作符之前的内容(包括操作符本身)不参与签名计算。注意,该语句行末没有 ;

contract TestSeparator {
    public function equal(int y) {
        int a = 0;
        // separator 1
        ***
        int b = 2;
        // separator 2
        *****
        require(y > 0);
    }
}

Access Modifiers

There are three types of access modifiers available to help restrict the scope of properties and functions of a contract:

  • Default: no keyword required
  • Private
  • Public: only applies to functions

Only public functions can be called externally by Bitcoin transactions.

  default private public
Same contract Yes Yes Yes
Other contract Yes No Yes
Externally No No Yes

操作符

优先级 操作符 关联性
1 - ! ~
2 * / %
3 + -
4 << >>
5 < <= > >=
6 == !=
7 &
8 ^
9 |
10 &&
11 ||
12 ? :

Operator &&, ||, and ? : use short-circuit evaluation.

作用域

sCrypt的作用域遵循C99和Solidity的现行作用域规则。外部作用域的变量会被内部作用域的同名变量覆盖。