Bags of Cells (BoC) и сериализация
Что такое BoC
Bag of Cells (BoC) — это бинарный формат сериализации дерева cells. BoC — это как JSON для TON: универсальный формат для передачи данных между нодами, контрактами и off-chain приложениями.
Cell tree (in memory):
Root
/ \
Ref0 Ref1
|
Ref0
BoC (serialized):
[header][cell_0][cell_1][cell_2][references_table]
Где используется BoC
| Контекст | Использование BoC |
|---|---|
| Транзакции | Message body сериализуется как BoC |
| State | Контрактный state хранится как BoC |
| Deploy | Code + initial data в state_init = BoC |
| API | Результаты get-methods возвращаются как BoC |
| Storage | Блоки и state snapshots = BoC файлы |
Сериализация данных в Cells
Builder и Slice
Для работы с cells используются два типа:
- Builder — для записи данных в cell (конструктор)
- Slice — для чтения данных из cell (парсер)
// Запись (Builder)
let cell = beginCell()
.storeUint(op_code, 32) // 32 bits — op code
.storeUint(query_id, 64) // 64 bits — query ID
.storeCoins(amount) // VarInt — amount
.storeAddress(recipient) // 267 bits — address
.endCell();
// Чтение (Slice)
let slice = cell.beginParse();
let op = slice.loadUint(32);
let qid = slice.loadUint(64);
let amt = slice.loadCoins();
let addr = slice.loadAddress();
Compact Encoding Strategies
TON использует компактные кодировки для экономии bits:
Design Implications
1. Message body design
Каждое сообщение имеет body — cell с данными. Проектируйте body заранее:
Standard Message Body Layout:
├── op_code: uint32 (какая операция)
├── query_id: uint64 (для tracking и idempotency)
└── payload: depends on op_code
Пример: Jetton Transfer
├── op: 0xf8a7ea5 (32 bits)
├── query_id: uint64 (64 bits)
├── amount: VarInt coins (≤124 bits)
├── destination: address (267 bits)
├── response_destination: address (267 bits)
├── custom_payload: Maybe ref
└── forward_ton_amount: VarInt coins
forward_payload: Maybe ref
Total: ~754 bits + optional refs
2. State layout optimization
Минимизируйте bits и cells в state:
[NO] Wasteful:
status: uint256 (256 bits для значения 0-5)
[OK] Optimized:
status: uint3 (3 bits для значения 0-5)
Saved: 253 bits per cell = меньше storage fee
3. BoC size влияет на forward fee
Forward fee пропорционально размеру BoC:
forward_fee = cells × cell_price + bits × bit_price
Меньше cells/bits в message → меньше forward fee → дешевле для пользователя
Practical Rule: pack tightly, reference wisely
Pack maximum data into each cell (use all 1023 bits). Use references only when data doesn’t fit or needs to be optional (Maybe). Every extra cell = extra storage fee + extra forward fee.