Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider utilizing RUNVM within Tact or elsehow to test and gas benchmark TVM instructions #1772

Open
novusnota opened this issue Feb 10, 2025 · 0 comments
Labels
feature: asm Tact-embedded assembly functions kind: gas! Gas consumption and fee-related things kind: performance Improve compiler/testing performance kind: testing Tests (*.spec.ts)

Comments

@novusnota
Copy link
Member

novusnota commented Feb 10, 2025

The RUNVM and RUNVMX are unique TVM instructions that allow running a sandboxed version of VM. See: https://docs.ton.org/v3/documentation/tvm/specification/runvm

import "@stdlib/deploy";

// --- The Program ---

contract BlankContract with Deployable {
    receive("gas, gas, gas!") {
        // VM Struct has exitCode and gasConsumed fields set to 0 by default
        expect(VM{ gasConsumed: 44 }, test1(), 1); // 26 (41 INT) + 18 (INC)
        expect(VM{ gasConsumed: 18 }, test2(), 1); // 18 (ONE)
        expect(VM{ gasConsumed: 72 }, test3(), 0); // 18 (ONE) + 18 (ONE) + 18 (ADD) + 18 (DROP)
        expect(VM{ gasConsumed: 36 }, test4(), 2); // 18 (1 INT) + 18 (1 INT)
    }
}

asm fun test1(): Slice {
    // The code to be evaluated should be self-contained within the `<{...}>s` block
    // and it must NOT consume any prior items from the stack.
    <{
        // For example, let's test INC with some new input to it:
        41 INT  // INT = PUSHINT
        INC     // INC = 1 ADDCONST
    }>s SLICE
}

asm fun test2(): Slice { <{ ONE }>s SLICE }
asm fun test3(): Slice { <{ ONE ONE ADD DROP }>s SLICE }
asm fun test4(): Slice { <{ 1 INT 2 INT }>s SLICE }

// --- Utility ---

struct VM {
    exitCode: Int = 0;
    gasConsumed: Int = 0;
}

fun expect(vmState: VM, code: Slice, toPushItemsNum: Int) {
    require(toPushItemsNum >= 0, "Specified number of items pushed is less than zero!");

    // Invoke VM
    let vmResult: VM = runvm(code, toPushItemsNum);

    // Actual values of the exit code and gas consumed by the VM
    // as well as the items produced by the VM right after
    // were seen in DUMPSTK output already.
    // 
    // Thus, it's ok to use following require() calls:

    // Exit code
    require(vmResult.exitCode != -3, "Number of items pushed is less than expected!");
    require(vmResult.exitCode != -14, "Inner VM went out of gas!");
    require(
        vmState.exitCode == vmResult.exitCode,
        "The expected exit code didn't match the actual one!",
    );
    
    // Gas
    require(
        vmState.gasConsumed == vmResult.gasConsumed,
        "The expected gas consuption didn't match the actual one!",
    );
}

asm fun runvm(code: Slice, newItemsCount: Int): VM {
    // Storing a copy of `newItemsCount` in register c7
    DUP
    c7 PUSH
    SWAP
    TPUSH
    c7 POP

    // Preparations
    ZERO        // don't touch prior stack items
    -ROT        // 0 code newItemsCount
    1000000 INT // gas_limit from config param 20

    // Invocation
    392 RUNVM   // 256 + 128 + 8, see: https://docs.ton.org/v3/documentation/tvm/specification/runvm
    5 SUBINT    // internal vm gas spends
    DUMPSTK     // to display results with expected VM state,
                // received values and actual VM state

    // Cleanup
    c7 PUSH
    SWAP TPUSH
    SWAP TPUSH  // to store the two items on top
    c7 PUSH
    LAST        // retrieve `newItemsCount`
    SWAP
    c7 POP      // keep the new c7 with 3 items by the end
    DROPX       // remove `newItemsCount` items from the stack
    c7 PUSH
    TPOP SWAP
    TPOP SWAP
    TPOP DROP
    c7 POP
}
@novusnota novusnota added feature: asm Tact-embedded assembly functions kind: gas! Gas consumption and fee-related things kind: testing Tests (*.spec.ts) kind: performance Improve compiler/testing performance labels Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature: asm Tact-embedded assembly functions kind: gas! Gas consumption and fee-related things kind: performance Improve compiler/testing performance kind: testing Tests (*.spec.ts)
Projects
None yet
Development

No branches or pull requests

1 participant