Хранение данных и get-методы
Резюме: На предыдущих этапах мы узнали, как использовать
Blueprint
и его структуру проекта.
Если вы застрянете на любом из примеров, вы можете найти исходный шаблон проекта со всеми изменениями, сделанными в этом руководстве, здесь.
Почти все смарт-контракты должны хранить свои данные
между транзакциями. В этом руководстве объясняются стандартные способы управления хранилищем
для смарт-контрактов и как использовать get-методы
для доступа к нему извне блокчейна.
Операции хранения в смарт-контрактах
- FunC
- Tolk
Есть две основные инструкции, обеспечивающие доступ к хранилищу смарт-контракта:
get_data()
возвращает текущую ячейку хранения.set_data()
записывает ячейку хранения.
Есть две основные инструкции, обеспе чивающие доступ к хранилищу смарт-контракта:
getContractData()
возвращает текущую `ячейку`` хранения.setContractData()
записываетячейку
хранения.
Давайте изучим структуру ячейки, чтобы понимать, как управлять хранилищем контракта:
Структура ячейки
Блокчейн TON использует структуру данных Ячейка в качестве фундаментальной единицы для хранения данных. Ячейки являются «строительными блоками» данных смарт-контрактов и обладают следующими характеристиками:
- Ячейка может хранить до 1023 бит (примерно 128 байт) данных.
- Ячейка может содержать ссылки на дочерние ячейки количеством до 4 штук.
- После своего создания Ячейка неизменяема.
Вы можете рассматривать Ячейку как следующую структуру:
// Conceptual representation of a Cell
interface Cell {
bits: BitString; // Up to 1023 bits
refs: Cell[]; // Up to 4 child cells
}
Реализация
Давайте изменим наш смарт-контракт в соответствии со стандартными шагами, описанными в разделе Обзор Blueprint.
Шаг 1: редактирование кода смарт-контракта
Если ручная сериализация и десериализация ячейки хранения становятся неудобны, стандартная практика заключается в создании двух методов-«обёрток», которые обрабатывают эту логику. Если вы не меняли код смарт-контракта, он должен включать следующие строки в /contracts/hello_world.fc
:
- FunC
- Tolk
global int ctx_id;
global int ctx_counter;
;; load_data присваивает значения переменным хранения, используя хранимые данные
() load_data() impure {
var ds = get_data().begin_parse();
ctx_id = ds~load_uint(32);
ctx_counter = ds~load_uint(32);
ds.end_parse();
}
;; save_data сохраняет значения переменных хранения в постоянное хранилище в формате ячейки
() save_data() impure {
set_data(
begin_cell()
. tore_uint(ctx_id, 32)
. tore_uint(ctx_counter, 32)
.end_cell()
);
}
global ctxID: int;
global ctxCounter: int;
// loadData populates storage variables from persistent storage
fun loadData() {
var ds = getContractData().beginParse();
ctxID = ds.loadUint(32);
ctxCounter = ds.loadUint(32);
ds.assertEndOfSlice();
}
// saveData stores storage variables as a cell into persistent storage
fun saveData() {
setContractData(
beginCell()
.storeUint(ctxID, 32)
.storeUint(ctxCounter, 32)
.endCell());
}