-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: size limits of a single contract
WIP: - [x] (more or less done) map size limits - [ ] max number of cells — there's an issue with Fift decompiler, blocking progress. Besides, the total limit from TON side is known: $2^{16}$ cells per account state, according to [config param 43](https://docs.ton.org/develop/howto/blockchain-configs#param-43) - [ ] max number of struct fields
- Loading branch information
Showing
6 changed files
with
578 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()}) |
Oops, something went wrong.