Storage and get methods
Summary: In the previous steps, we learned how to use the
Blueprintand its project structure.
If you're stuck on any of the examples, you can find the original template project with all modifications made during this guide here.
Almost all smart contracts need to store their data between transactions. This guide explains standard ways to manage storage for smart contracts and how to use get methods to access it outside the blockchain.
Smart contract storage operations
- FunC
- Tolk
There are two main instructions that provide access to smart contract storage:
get_data()returning the current storage cell.set_data()setting storage cell.
There are two main instructions that provide access to smart contract storage:
getContractData()returning current storageCell.setContractData()setting storageCell.
Let's examine the Cell structure to understand how to manage contract storage:
Cell structure
TON Blockchain uses a data structure called Cell as the fundamental unit for storing data. Cells are the building blocks of smart contract data and have the following characteristics:
- A Cell can store up to 1023 bits (approximately 128 bytes) of data.
- A Cell can reference up to 4 other Cells (children).
- A Cell is immutable once created.
You can think of a Cell as the following structure:
// Conceptual representation of a Cell
interface Cell {
bits: BitString; // Up to 1023 bits
refs: Cell[]; // Up to 4 child cells
}
Implementation
Let's modify our smart contract by following the standard steps described in the previous Blueprint overview section.
Step 1: edit smart contract code
If manually serializing and deserializing the storage cell becomes inconvenient, a common practice is to define two wrapper methods that handle this logic. If you haven't modified the smart contract code, it should include the following lines in the /contracts/hello_world.fc:
- FunC
- Tolk
global int ctx_id;
global int ctx_counter;
;; load_data populates storage variables using stored 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 stores storage variables as a cell into persistent storage
() save_data() impure {
set_data(
begin_cell()
.store_uint(ctx_id, 32)
.store_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());
}