Move VM 是一个栈式虚拟机

相关代码:sui/external-crates/move at main · MystenLabs/sui (github.com)

解释器:sui/external-crates/move/crates/move-vm-runtime/src/interpreter.rs · MystenLabs/sui (github.com)

合约在被部署时,bytecode就会被多个verifier验证[1],如类型匹配之类的检查就是在此时进行,程序被部署后,就可以省去运行时类型检查,只需要检查传入合约的参数是否符合类型要求

sui的官方反汇编器位于:sui/external-crates/move/crates/move-disassembler at main · MystenLabs/sui (github.com),可用于反汇编

下方是一个例子:

    public entry fun solve(
        status: &mut SolveStatus,
        fake_coin: FakeCoin,
        real_coin: Coin<ZCOIN>,
        ctx: &mut TxContext
    ) {
        let mark_: u64 = 0x1111111111111111;
        let mut v: vector<Coin<ZCOIN>> = vector[real_coin];
        let c: Coin<ZCOIN> = vector::pop_back(&mut v);
        vector::destroy_empty(v);

        zcoin::solve(status, c, ctx);

        let sender = sender(ctx);
        let mark_: u64 = 0x2222222222222222;
        transfer::public_transfer(fake_coin, sender);
    }
entry public solve(Arg0: &mut SolveStatus, Arg1: FakeCoin, Arg2: Coin<ZCOIN>, Arg3: &mut TxContext) {
        // arg0/1/2 is stored as local var (index 0-2)
B0:
        0: LdU64(1229782938247303441)                           // push imm into stack
        1: Pop
        2: MoveLoc[2](Arg2: Coin<ZCOIN>)                        // push local var (index: 2) into stack
        3: VecPack(10, 1)                                       // create vector (10: SignatureIndex (type info), 1: initial object cnt, will pop from stack) and push into stack
        4: StLoc[6](loc2: vector<Coin<ZCOIN>>)                  // pop object from stack and store as local var (index: 6)
        5: MutBorrowLoc[6](loc2: vector<Coin<ZCOIN>>)           // mut borrow local var and push into stack
        6: VecPopBack(10)                                       // pop back from vec (10: SignatureIndex)
        7: StLoc[4](loc0: Coin<ZCOIN>)
        8: MoveLoc[6](loc2: vector<Coin<ZCOIN>>)
        9: VecUnpack(10, 0)                                     // unpack/destroy vector, and pop all items in it (10: SignatureIndex, 0: item cnt)
        10: MoveLoc[0](Arg0: &mut SolveStatus)
        11: MoveLoc[4](loc0: Coin<ZCOIN>)
        12: CopyLoc[3](Arg3: &mut TxContext)                    // copy local var and push into stack
        13: Call zcoin::solve(&mut SolveStatus, Coin<ZCOIN>, &mut TxContext) // normal Call, args will be fetch from stack, operand `FunctionHandleIndex` not print by disassembler
        14: MoveLoc[3](Arg3: &mut TxContext)
        15: FreezeRef
        16: Call tx_context::sender(&TxContext): address
        17: StLoc[5](loc1: address)
        18: LdU64(2459565876494606882)
        19: Pop
        20: MoveLoc[1](Arg1: FakeCoin)
        21: MoveLoc[5](loc1: address)
        22: Call transfer::public_transfer<FakeCoin>(FakeCoin, address) // actually CallGeneric, operand `FunctionInstantiationIndex` not print by disassembler
        23: Ret
}

大部分小括号中的内容都是反汇编器进行的类型推导,并不真正存在于bytecode中 (Vec相关的指令除外,那些小括号中的是真的operand…)

Bytecode序列化源码:sui/external-crates/move/crates/move-binary-format/src/serializer.rs · MystenLabs/sui (github.com)

Bytecode编码 建议不要看代码,直接对照源码和Bytecode基本就能看懂,实在不行在像分析的指令前放上一句标识语句(例如上面的_mark,有巨大imm,很容易找到)

部署bytecode参考:部署Bytecode

参考:

  1. The Billion Dollar Bug: Finding and Fixing a Critical Issue in the Move Bytecode Verifier | Zellic — Research