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

fix(codegen): allocator not accounting for extra ref in a cell resulting in cell overflows in some cases #615

Merged
merged 2 commits into from
Jul 24, 2024
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Defining non-existing native FunC functions now throws an understandable compilation error: PR [#585](https://github.com/tact-lang/tact/pull/585)
- Bump used `@tact-lang/opcode` version to `0.0.16` which fixes the issue with `DIV` instructions: PR [#589](https://github.com/tact-lang/tact/pull/589)
- Incorrect FunC code generated for `recv_external`: PR [#604](https://github.com/tact-lang/tact/pull/604)
- Allocator bug resulting in cell overflows for some contract data layouts: PR [#615](https://github.com/tact-lang/tact/pull/615)

## [1.4.0] - 2024-06-21

Expand Down
12 changes: 6 additions & 6 deletions examples/__snapshots__/increment.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ exports[`increment should deploy 1`] = `
},
"bounce": true,
"from": "@treasure(treasure)",
"to": "kQCFVwtFcoSZ-muVDfXKSpI0fzDrWMuzTgXqo4_QDKKycmXS",
"to": "kQCZq6o-nSHCoxfIzdCAl3fDePr-LEYT-VUlqbQ5prvrJ7Y2",
"type": "internal",
"value": "10",
},
},
{
"$type": "processed",
"gasUsed": 8491n,
"gasUsed": 8473n,
},
{
"$type": "sent",
Expand All @@ -41,10 +41,10 @@ exports[`increment should deploy 1`] = `
},
},
"bounce": false,
"from": "kQCFVwtFcoSZ-muVDfXKSpI0fzDrWMuzTgXqo4_QDKKycmXS",
"from": "kQCZq6o-nSHCoxfIzdCAl3fDePr-LEYT-VUlqbQ5prvrJ7Y2",
"to": "@treasure(treasure)",
"type": "internal",
"value": "9.990313",
"value": "9.990331",
},
],
},
Expand All @@ -71,14 +71,14 @@ exports[`increment should deploy 2`] = `
},
"bounce": true,
"from": "@treasure(treasure)",
"to": "kQCFVwtFcoSZ-muVDfXKSpI0fzDrWMuzTgXqo4_QDKKycmXS",
"to": "kQCZq6o-nSHCoxfIzdCAl3fDePr-LEYT-VUlqbQ5prvrJ7Y2",
"type": "internal",
"value": "10",
},
},
{
"$type": "processed",
"gasUsed": 6007n,
"gasUsed": 5963n,
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13007,8 +13007,8 @@ return result;",
"code": "var (v'a, v'b, v'c, v'd, v'e, v'f, v'g, v'h) = v;
build_0 = build_0.store_ref(v'a);
build_0 = ~ null?(v'b) ? build_0.store_int(true, 1).store_ref(v'b) : build_0.store_int(false, 1);
build_0 = ~ null?(v'c) ? build_0.store_int(true, 1).store_ref(begin_cell().store_slice(v'c).end_cell()) : build_0.store_int(false, 1);
var build_1 = begin_cell();
build_1 = ~ null?(v'c) ? build_1.store_int(true, 1).store_ref(begin_cell().store_slice(v'c).end_cell()) : build_1.store_int(false, 1);
build_1 = ~ null?(v'd) ? build_1.store_int(true, 1).store_ref(begin_cell().store_slice(v'd).end_cell()) : build_1.store_int(false, 1);
build_1 = build_1.store_int(v'e, 1);
build_1 = build_1.store_int(v'f, 257);
Expand Down Expand Up @@ -13837,8 +13837,8 @@ if (null?(loaded)) {
"code": {
"code": "var v'a = sc_0~load_ref();
var v'b = sc_0~load_int(1) ? sc_0~load_ref() : null();
var v'c = sc_0~load_int(1) ? sc_0~load_ref().begin_parse() : null();
slice sc_1 = sc_0~load_ref().begin_parse();
var v'c = sc_1~load_int(1) ? sc_1~load_ref().begin_parse() : null();
var v'd = sc_1~load_int(1) ? sc_1~load_ref().begin_parse() : null();
var v'e = sc_1~load_int(1);
var v'f = sc_1~load_int(257);
Expand Down
32 changes: 16 additions & 16 deletions src/storage/__snapshots__/resolveAllocation.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -465,12 +465,12 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 514,
"refs": 0,
"refs": 1,
},
},
"size": {
"bits": 514,
"refs": 0,
"refs": 1,
},
},
"type": {
Expand Down Expand Up @@ -867,7 +867,7 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
},
"ops": [
Expand Down Expand Up @@ -916,7 +916,7 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
},
"ops": [
Expand Down Expand Up @@ -965,12 +965,12 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
},
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
},
"type": {
Expand Down Expand Up @@ -1667,7 +1667,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1685,7 +1685,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1703,7 +1703,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1727,7 +1727,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1740,7 +1740,7 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
},
"ops": [
Expand All @@ -1752,7 +1752,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1765,7 +1765,7 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 2,
},
},
"ops": [
Expand All @@ -1777,7 +1777,7 @@ exports[`resolveAllocation should write program 1`] = `
"ref": false,
"size": {
"bits": 771,
"refs": 0,
"refs": 1,
},
"type": "Deep",
},
Expand All @@ -1790,12 +1790,12 @@ exports[`resolveAllocation should write program 1`] = `
],
"size": {
"bits": 771,
"refs": 0,
"refs": 2,
},
},
"size": {
"bits": 771,
"refs": 0,
"refs": 2,
},
},
"type": {
Expand Down
21 changes: 16 additions & 5 deletions src/storage/allocator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,16 +301,27 @@ function allocateSegment(
let next: AllocationCell | null = null;
const used: { bits: number; refs: number } = { bits: 0, refs: 0 };

const [totalBits, totalRefs] = ops.reduce(
([sumBits, sumRefs], op) => {
const opSize = getOperationSize(op.op);
return [sumBits + opSize.bits, sumRefs + opSize.refs];
},
[0, 0],
);
// check if there will be a new allocation segment,
// meaning we need to have a spare ref to link it
// from the current segment
if (totalBits > bits || totalRefs > refs) {
refs -= 1;
}

for (const [i, op] of ops.entries()) {
const size = getOperationSize(op.op);

// Check if we can fit this operation
if (size.bits > bits || size.refs > refs) {
next = allocateSegment(
ops.slice(i),
1023 - ALLOCATOR_RESERVE_BIT,
4 - ALLOCATOR_RESERVE_REF,
);
used.refs += 1;
next = allocateSegment(ops.slice(i), 1023, 4);
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ exports[`intrinsics should return correct intrinsic results 1`] = `
},
{
"$type": "processed",
"gasUsed": 7881n,
"gasUsed": 7915n,
},
{
"$type": "sent",
Expand Down
6 changes: 3 additions & 3 deletions src/test/e2e-emulated/__snapshots__/map.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ exports[`map should implement maps correctly 1`] = `
},
"bounce": true,
"from": "@treasure(treasure)",
"to": "kQDF6S3qUJdr9fVijosUCNJyi5YNnAe1KvoyKjWqsnky6crw",
"to": "kQA9A-B3CjPFrYe-tOHzjlnaFNzrG5eTlY2AmsgtGfkzSLTM",
"type": "internal",
"value": "1",
},
Expand All @@ -36,10 +36,10 @@ exports[`map should implement maps correctly 1`] = `
"type": "cell",
},
"bounce": false,
"from": "kQDF6S3qUJdr9fVijosUCNJyi5YNnAe1KvoyKjWqsnky6crw",
"from": "kQA9A-B3CjPFrYe-tOHzjlnaFNzrG5eTlY2AmsgtGfkzSLTM",
"to": "@treasure(treasure)",
"type": "internal",
"value": "0.981951",
"value": "0.982029",
},
},
],
Expand Down
32 changes: 32 additions & 0 deletions src/test/e2e-emulated/allocation.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { toNano } from "@ton/core";
import { ContractSystem } from "@tact-lang/emulator";
import { Test } from "./contracts/output/allocation_Test";

describe("allocation", () => {
it("should deploy correctly and process SetCost message without cell overflow", async () => {
const system = await ContractSystem.create();
const owner = system.treasure("owner");
const contract = system.open(
await Test.fromInit(owner.address, {
$$type: "Struct2",
c: "",
d: "",
e: "",
f: "",
}),
);
system.name(contract.address, "main");
await contract.send(
owner,
{ value: toNano(1) },
{ $$type: "Deploy", queryId: 0n },
);
await system.run();
await contract.send(
owner,
{ value: toNano(1) },
{ $$type: "SetCost", cost: toNano("0.1") },
);
await system.run();
});
});
37 changes: 37 additions & 0 deletions src/test/e2e-emulated/contracts/allocation.tact
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import "@stdlib/deploy";

message SetCost {
cost: Int? as coins;
}

struct Struct2 {
c: String;
d: String;
e: String;
f: String;
}

contract Test with Deployable {
owner: Address;
seqno: Int as uint256 = 0;
a: Int as uint256 = 0;
b: Int as uint256 = 0;

struct2: Struct2;

author3: Address?;

cost: Int? as coins;
address: Address?;
price: Int? as coins;

init(owner: Address, struct2: Struct2) {
self.owner = owner;
self.struct2 = struct2;
}

receive(msg: SetCost) {
self.cost = msg.cost;
self.reply("Cost is updated".asComment());
}
}
5 changes: 5 additions & 0 deletions tact.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,11 @@
"name": "getter-names-conflict",
"path": "./src/test/e2e-emulated/contracts/getter-names-conflict.tact",
"output": "./src/test/e2e-emulated/contracts/output"
},
{
"name": "allocation",
"path": "./src/test/e2e-emulated/contracts/allocation.tact",
"output": "./src/test/e2e-emulated/contracts/output"
}
]
}
Loading