Skip to content

Commit

Permalink
test: Tact-reserved and general compute phase exit codes (#823)
Browse files Browse the repository at this point in the history
With the correction of error list generated for the `.md` compilation
report
  • Loading branch information
novusnota authored Sep 15, 2024
1 parent a470488 commit b6c65a4
Show file tree
Hide file tree
Showing 11 changed files with 692 additions and 6 deletions.
6 changes: 6 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"lvalues",
"masterchain",
"maxint",
"Merkle",
"minmax",
"mintable",
"mktemp",
Expand All @@ -92,13 +93,15 @@
"Offchain",
"Parens",
"pinst",
"PLDDICT",
"PLDIX",
"PLDREF",
"PLDSLICEX",
"PLDUX",
"POSIX",
"postpack",
"prando",
"PUSHINT",
"PUSHREF",
"PUSHSLICE",
"RANDU",
Expand All @@ -120,7 +123,9 @@
"SENDRAWMSG",
"SENDMSG",
"seqno",
"SETCONTARGS",
"SETINDEXVARQ",
"SETNUMARGS",
"shiki",
"SREFS",
"SREMPTY",
Expand Down Expand Up @@ -177,6 +182,7 @@
"src/test/e2e-emulated/contracts/strings.tact",
"src/test/compilation-fail/fail-const-eval.spec.ts",
"src/test/e2e-emulated/getter-names-conflict.spec.ts",
"src/test/exit-codes/contracts/compute-phase-errors.tact",
"stdlib/stdlib.fc"
]
}
21 changes: 20 additions & 1 deletion src/generator/createABI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,30 @@ export function createABI(ctx: CompilerContext, name: string): ContractABI {
errors["8"] = { message: "Cell overflow" };
errors["9"] = { message: "Cell underflow" };
errors["10"] = { message: "Dictionary error" };
errors["11"] = { message: "'Unknown' error" };
errors["12"] = { message: "Fatal error" };
errors["13"] = { message: "Out of gas error" };
errors["32"] = { message: "Method ID not found" };
errors["14"] = { message: "Virtualization error" };
errors["32"] = { message: "Action list is invalid" };
errors["33"] = { message: "Action list is too long" };
errors["34"] = { message: "Action is invalid or not supported" };
errors["35"] = { message: "Invalid source address in outbound message" };
errors["36"] = {
message: "Invalid destination address in outbound message",
};
errors["37"] = { message: "Not enough TON" };
errors["38"] = { message: "Not enough extra-currencies" };
errors["39"] = {
message: "Outbound message does not fit into a cell after rewriting",
};
errors["40"] = { message: "Cannot process a message" };
errors["41"] = { message: "Library reference is null" };
errors["42"] = { message: "Library change action error" };
errors["43"] = {
message:
"Exceeded maximum number of cells in the library or the maximum depth of the Merkle tree",
};
errors["50"] = { message: "Account state size exceeded limits" };
for (const e of Object.values(contractErrors)) {
errors[e.id] = { message: e.message };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ exports[`local-type-inference should automatically set types for let statements
"10": {
"message": "Dictionary error",
},
"11": {
"message": "'Unknown' error",
},
"12": {
"message": "Fatal error",
},
"128": {
"message": "Null reference exception",
},
Expand Down Expand Up @@ -39,30 +45,60 @@ exports[`local-type-inference should automatically set types for let statements
"137": {
"message": "Masterchain support is not enabled for this contract",
},
"14": {
"message": "Virtualization error",
},
"2": {
"message": "Stack underflow",
},
"3": {
"message": "Stack overflow",
},
"32": {
"message": "Method ID not found",
"message": "Action list is invalid",
},
"33": {
"message": "Action list is too long",
},
"34": {
"message": "Action is invalid or not supported",
},
"35": {
"message": "Invalid source address in outbound message",
},
"36": {
"message": "Invalid destination address in outbound message",
},
"37": {
"message": "Not enough TON",
},
"38": {
"message": "Not enough extra-currencies",
},
"39": {
"message": "Outbound message does not fit into a cell after rewriting",
},
"4": {
"message": "Integer overflow",
},
"40": {
"message": "Cannot process a message",
},
"41": {
"message": "Library reference is null",
},
"42": {
"message": "Library change action error",
},
"43": {
"message": "Exceeded maximum number of cells in the library or the maximum depth of the Merkle tree",
},
"5": {
"message": "Integer out of expected range",
},
"50": {
"message": "Account state size exceeded limits",
},
"6": {
"message": "Invalid opcode",
},
Expand Down
151 changes: 151 additions & 0 deletions src/test/exit-codes/compute-phase-errors.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { toNano } from "@ton/core";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
import {
ComputePhaseErrorsTester as TestContract,
ExitCode4,
} from "./contracts/output/compute-phase-errors_ComputePhaseErrorsTester";
import "@ton/test-utils";

describe("compute phase errors", () => {
let blockchain: Blockchain;
let treasure: SandboxContract<TreasuryContract>;
let contract: SandboxContract<TestContract>;

beforeEach(async () => {
blockchain = await Blockchain.create();
blockchain.verbosity.print = false;
treasure = await blockchain.treasury("treasure", {
resetBalanceIfZero: true,
});

contract = blockchain.openContract(await TestContract.fromInit());

const deployResult = await contract.send(
treasure.getSender(),
{ value: toNano("10000") },
null,
);

expect(deployResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: true,
deploy: true,
});
});

// 0: success
it("should test exit code 0", async () => {
await testComputePhaseExitCode(0, contract, treasure);
});

// 1: alt. success code
it("should test exit code 1", async () => {
await testComputePhaseExitCode(1, contract, treasure);
});

// 2: stack underflow
it("should test exit code 2", async () => {
await testComputePhaseExitCode(2, contract, treasure);
});

// 3: Stack overflow
it("should test exit code 3", async () => {
await testComputePhaseExitCode(3, contract, treasure);
});

// 4: Integer overflow
it("should test exit code 4", async () => {
await testComputePhaseExitCode(4, contract, treasure);
});

// 5: Integer out of range
it("should test exit code 5", async () => {
await testComputePhaseExitCode(5, contract, treasure);
});

// 6: Invalid opcode
it("should test exit code 6", async () => {
await testComputePhaseExitCode(8, contract, treasure);
});

// 7: Type check error
it("should test exit code 7", async () => {
await testComputePhaseExitCode(7, contract, treasure);
});

// 8: Cell overflow
it("should test exit code 8", async () => {
await testComputePhaseExitCode(8, contract, treasure);
});

// 9: Cell underflow
it("should test exit code 9", async () => {
await testComputePhaseExitCode(9, contract, treasure);
});

// 10: Dictionary error
it("should test exit code 10", async () => {
await testComputePhaseExitCode(10, contract, treasure);
});

// 11: "Unknown" error
// NOTE: Thrown in various unrelated cases
it("should test exit code 11", async () => {
await testComputePhaseExitCode(11, contract, treasure);
});

// 12: Fatal error
// NOTE: thrown by TVM in situations deemed impossible

// 13 (actually, -14): Out of gas
it("should test exit code 13", async () => {
await testComputePhaseExitCode(13, contract, treasure);
});

// 14: Virtualization error
// NOTE: Reserved, but never thrown
});

async function testComputePhaseExitCode(
code: number,
contract: SandboxContract<TestContract>,
treasure: SandboxContract<TreasuryContract>,
) {
expect(code).toBeGreaterThanOrEqual(0);
expect(code).toBeLessThan(128);
expect([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13]).toContain(code);
type testedExitCodes =
| "0"
| "1"
| "2"
| "3"
| ExitCode4
| "5"
| "6"
| "7"
| "8"
| "9"
| "10"
| "11"
| "13";

const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
code === 4
? {
$$type: "ExitCode4",
val0: BigInt(0),
val1: BigInt(1),
}
: (code.toString(10) as testedExitCodes),
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: code === 0 || code === 1 ? true : false,
exitCode: code === 13 ? -14 : code,
});
}
8 changes: 8 additions & 0 deletions src/test/exit-codes/contracts/compute-phase-errors.fc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
() stack_overflow() impure asm """
<{
}>CONT // c
0 SETNUMARGS // c'
2 PUSHINT // c' 2
SWAP // 2 c'
1 -1 SETCONTARGS
""";
Loading

0 comments on commit b6c65a4

Please sign in to comment.