内联汇编

脚本是一种低级语言,充当 比特币虚拟机 的程序集。通常,开发人员不必直接处理它,可以使用 sCrypt 等高级语言。但是,有些情况下需要使用 Script。例如,自定义脚本经过优化,因此比 sCrypt 生成的脚本更高效。或者脚本是使用外部工具(如 MiniForth)生成的,需要集成到sCrypt中。

用汇编表示法可以直接把脚本嵌入到sCrypt源代码中。可以用脚本编写sCrypt函数,并像正常的sCrypt函数一样被调用。

调用约定

对于用脚本编写的函数,它的整个函数主体必须用 asm 块包围。函数参数位于栈顶,与声明的顺序相反。例如,对于签名为 function foo(int p0, bytes p1, bool p2) : int 的函数,p2 位于栈顶,p1 是从栈顶倒数第二个,而 p0 进入 asm 是第三个。当退出 asm 模式时,需要弹出栈里的所有参数,并把返回值放到栈顶。栈里其他元素保持不变。

三个汇编函数如下所示。

// compute length of "b" in bytes
function len(bytes b): int {
    asm {
        op_size
    }
}

// this is also fine since the return is on top and none in the old stack is changed
function len(bytes b): int {
    asm {
        op_size
        op_nip
    }
}

function lenFail(bytes b): int {
    // this is wrong since the original top of stack is dropped
    asm {
        op_drop
        op_size
    }
}

汇编变量

变量可以通过前缀 $asm 模式中使用。与脚本的其余部分不同,它被完整复制到最终脚本输出中,变量以其作用域为前缀以避免名称冲突,由它所在的函数和契约唯一标识。例如,假设在合约 contractFoo 内的函数 func 中使用了一个变量 $var,它将在最终的脚本输出中显示为 $contractFoo.func.var

一个例子如下所示。

function p2pkh(Sig sig, PubKey pubKey): bool {
    asm {
        op_dup
        op_hash160
        $pkh
        op_equalverify
        op_checksig
    }
}

循环

循环语法 也可以在 asm 中使用。

public function unlock(int x) {
    asm {
        OP_DUP
        loop (N) : i {
            loop (N) : j {
                i
                j
                OP_ADD
                OP_ADD
            }
        }
        13
        OP_NUMEQUAL
        OP_NIP
    }
}

等价的 sCrypt 代码是:

public function unlock(int x) {
    int sum = x;
    loop (N) : i {
        loop (N) : j {
            sum += (i + j);
        }
    }
    require(sum == 0x13);
}

ij归纳变量

字符串

字符串是一个双引号 UTF8 字符串,可以在 asm 中使用。

static function equal(bytes msg) : bool {
    asm {
        "你好world! 😊"
        OP_EQUAL
    }
}

注意

内联汇编绕过了 sCrypt 的许多功能,例如类型检查。使用此高级功能时必须格外小心。此外,为了与外部工具兼容,它不区分大小写。