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

test: size limits of a single contract #817

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions src/test/size-limits/cells.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { toNano } from "@ton/core";
import { Blockchain, SandboxContract, TreasuryContract } from "@ton/sandbox";
import { MaxCellNumberTester as TestContract } from "./contracts/output/cell-number-limits_MaxCellNumberTester";
import "@ton/test-utils";

// According to config param 43, the absolute max is 2^16 cells by default
// The test below is used to know what's the max for Tact contracts
describe("cell number limits", () => {
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", {
balance: 1_000_000_000n,
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,
});
});

it("should test cell number limits", async () => {
// TODO: a test, that adds more cells to the mix.
const sendResult = await contract.send(
treasure.getSender(),
{ value: toNano("1") },
null, // FIXME: ← placeholder, until issues with Fift decompiler of the contract are resolved
// {
// $$type: "AddCells",
// number: BigInt(16), // NOTE: adjust
// },
);
expect(sendResult.transactions).toHaveTransaction({
from: treasure.address,
to: contract.address,
success: false,
actionResultCode: 50,
});
});
});
52 changes: 52 additions & 0 deletions src/test/size-limits/contracts/cell-number-limits.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// giantNestedCell
import "./giant-nested-cell.tact";

message AddCells { number: Int as uint8 }

contract MaxCellNumberTester {
c1: Cell; c2: Cell; c3: Cell; c4: Cell;
c5: Cell; c6: Cell; c7: Cell; c8: Cell;
c9: Cell; c10: Cell; c11: Cell; c12: Cell;
c13: Cell; c14: Cell; c15: Cell; c16: Cell;
cExtra: Cell;

// NOTE: for some reason, Fift's BoC cannot handle neither 2^13 nor 2^12 cells.
// It just breaks 1k cells short of deserializing each. May be an issue of this wasm fift version (we may need to upgrade it to recently released 2024.09 version)

/// Setup
init() {
self.c1 = giantNestedCell; // 2^{12} - 2 empty cells
self.c2 = giantNestedCell; // 2^{12} - 2 empty cells
self.c3 = giantNestedCell; // 2^{12} - 2 empty cells
self.c4 = giantNestedCell; // 2^{12} - 2 empty cells
self.c5 = giantNestedCell; // 2^{12} - 2 empty cells
self.c6 = giantNestedCell; // 2^{12} - 2 empty cells
self.c7 = giantNestedCell; // 2^{12} - 2 empty cells
self.c8 = giantNestedCell; // 2^{12} - 2 empty cells
self.c9 = giantNestedCell; // 2^{12} - 2 empty cells
self.c10 = giantNestedCell; // 2^{12} - 2 empty cells
self.c11 = giantNestedCell; // 2^{12} - 2 empty cells
self.c12 = giantNestedCell; // 2^{12} - 2 empty cells
self.c13 = giantNestedCell; // 2^{12} - 2 empty cells
self.c14 = giantNestedCell; // 2^{12} - 2 empty cells
self.c15 = giantNestedCell; // 2^{12} - 2 empty cells
self.c16 = giantNestedCell; // 2^{12} - 2 empty cells
self.cExtra = emptyCell(); // 1 empty cell
// Overall: 2^{16} - 2^{4} + 1 = 65520 cells
}

/// To handle deployment
receive() {}

/// To add X cells
receive(msg: AddCells) {
let b = beginCell().storeRef(emptyCell());

// 2 in b, 1 in cExtra already, and X in msg.number, therefore: X - (2 - 1)
repeat (msg.number - 1) {
b = beginCell().storeRef(b.endCell());
}

self.cExtra = b.endCell();
}
}
1 change: 1 addition & 0 deletions src/test/size-limits/contracts/giant-nested-cell.tact

Large diffs are not rendered by default.

165 changes: 165 additions & 0 deletions src/test/size-limits/contracts/map-size-limits.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
//
// map<Int, Int>
//

message AddIntInt {
batchSize: Int as uint8;
startingValue: Int as uint16;
}

contract MapIntInt {
/// Target map
m: map<Int as uint16, Int as uint16>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntInt) {
let curVal = msg.startingValue;
repeat (msg.batchSize) {
self.m.set(curVal, curVal);
curVal += 1;
}
}
}

//
// map<Int, Bool>
//

message AddIntBool {
batchSize: Int as uint8;
startingKey: Int;
}

contract MapIntBool {
/// Target map
m: map<Int, Bool>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntBool) {
let curVal = msg.startingKey;
repeat (msg.batchSize) {
self.m.set(curVal, false);
curVal += 1;
}
}
}

//
// map<Int, Cell>
//

message AddIntCell {
batchSize: Int as uint8;
startingKey: Int;
}

contract MapIntCell {
/// Target map
m: map<Int, Cell>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntCell) {
let curVal = msg.startingKey;
repeat (msg.batchSize) {
self.m.set(curVal, emptyCell());
curVal += 1;
}
}
}

//
// map<Int, Address>
//

message AddIntAddress {
batchSize: Int as uint8;
startingKey: Int;
}

contract MapIntAddress {
/// Target map
m: map<Int, Address>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntAddress) {
let curVal = msg.startingKey;
let myAddr = myAddress(); // TODO: different addresses
repeat (msg.batchSize) {
self.m.set(curVal, myAddr);
curVal += 1;
}
}
}

//
// map<Int, Struct>
//

message AddIntStruct {
batchSize: Int as uint8;
startingKey: Int;
}

struct BoolBool { yes: Bool }

contract MapIntStruct {
/// Target map
m: map<Int, BoolBool>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntStruct) {
let curVal = msg.startingKey;
let stBool = BoolBool{ yes: true };
repeat (msg.batchSize) {
self.m.set(curVal, stBool);
curVal += 1;
}
}
}

//
// map<Int, Message>
//

message AddIntMessage {
batchSize: Int as uint8;
startingKey: Int;
}

message(0x2A) TheAnswer {}

contract MapIntMessage {
/// Target map
m: map<Int, TheAnswer>;

/// To handle deployment
receive() {}

/// To add an item
receive(msg: AddIntMessage) {
let curVal = msg.startingKey;
let msgEmpty = TheAnswer{};
repeat (msg.batchSize) {
self.m.set(curVal, msgEmpty);
curVal += 1;
}
}
}

// TODO: all the same, but with Addresses as keys.
// NOTE: contractAddress(StateInit{code: emptyCell(), data: beginCell().storeUint(curVal, 16).endCell()})
Loading
Loading