Skip to content

Commit

Permalink
fix(codegen): allocator not accounting for extra ref in a cell result…
Browse files Browse the repository at this point in the history
…ing in cell overflows in some cases (#615)

resulting in cell overflows in some cases
  • Loading branch information
anton-trunov authored Jul 24, 2024
1 parent d1abeae commit 9b003bd
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 33 deletions.
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"
}
]
}

0 comments on commit 9b003bd

Please sign in to comment.