Skip to content

Commit

Permalink
test: Tact-reserved and general compute phase exit codes
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 committed Sep 14, 2024
1 parent 926edb4 commit cb9db97
Show file tree
Hide file tree
Showing 10 changed files with 717 additions and 5 deletions.
6 changes: 6 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"lvalues",
"masterchain",
"maxint",
"Merkle",
"minmax",
"mintable",
"mktemp",
Expand All @@ -90,13 +91,15 @@
"Offchain",
"Parens",
"pinst",
"PLDDICT",
"PLDIX",
"PLDREF",
"PLDSLICEX",
"PLDUX",
"POSIX",
"postpack",
"prando",
"PUSHINT",
"PUSHREF",
"PUSHSLICE",
"RANDU",
Expand All @@ -118,7 +121,9 @@
"SENDRAWMSG",
"SENDMSG",
"seqno",
"SETCONTARGS",
"SETINDEXVARQ",
"SETNUMARGS",
"shiki",
"SREFS",
"SREMPTY",
Expand Down Expand Up @@ -175,6 +180,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
248 changes: 248 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,248 @@
import { toNano } from "@ton/core";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
import { ComputePhaseErrorsTester as TestContract } 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("100000") },
null,
);

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

// 0: success
it("should test exit code 0", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"0",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: true,
exitCode: 0,
});
});

// 1: alt. success code
it("should test exit code 1", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"1",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: true,
exitCode: 1,
});
});

// 2: stack underflow
it("should test exit code 2", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"2",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 2,
});
});

// 3: Stack overflow
it("should test exit code 3", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"3",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 3,
});
});

// 4: Integer overflow
it("should test exit code 4", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"4",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 4,
});
});

// 5: Integer out of range
it("should test exit code 5", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"5",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 5,
});
});

// 6: Invalid opcode
it("should test exit code 6", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"6",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 6,
});
});

// 7: Type check error
it("should test exit code 7", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"7",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 7,
});
});

// 8: Cell overflow
it("should test exit code 8", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"8",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 8,
});
});

// 9: Cell underflow
it("should test exit code 9", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"9",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 9,
});
});

// 10: Dictionary error
it("should test exit code 10", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"10",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 10,
});
});

// 11: "Unknown" error
// NOTE: Thrown in various unrelated cases
it("should test exit code 11", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"11",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: 11,
});
});

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

// 13 (actually, -14): Out of gas
it("should test exit code 13", async () => {
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("10") },
"13",
);

expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
exitCode: -14,
});
});

// 14: Virtualization error
// NOTE: Reserved, but never thrown
});
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 cb9db97

Please sign in to comment.