Розробка модульного стеку (execution + DA + settlement)
Монолітний блокчейн робить все сам: виконує транзакції, забезпечує доступність даних, фіналізує стан. Модульний підхід розбиває ці функції між спеціалізованими шарами. Результат — екосистема, де можна вибирати компоненти як модулі: Celestia для DA, Ethereum для settlement, OP Stack або Arbitrum Orbit для execution. Це не теорія — так будуються десятки mainnet L2 та L3 у 2024–2025 році.
Типичний запит: «хочемо свій appchain з низькими комісіями і кастомною логікою, але з безпекою Ethereum». Це правильно сформульована задача, і модульний стек — правильна відповідь на неї.
Шари й їхні ролі
Execution Layer
Виконує транзакції, поддерживает стан. Це ваш ланцюг — зі своїми правилами, gas токеном, precompiles.
OP Stack (Optimism, Base, Zora) — найзрілніший фреймворк для Optimistic Rollup-based L2/L3. EVM-еквівалентність. op-geth + op-node + op-batcher + op-proposer.
Arbitrum Orbit — Arbitrum-based L2/L3. Підтримує Stylus (WASM смарт-контракти на Rust/C++). Більш гнучка кастомізація gas, permission models.
Polygon CDK — ZK-based chain development kit. zkEVM під капотом. Складніше в експлуатації, але ZK finality замість fraud window.
Sovereign rollup через Rollkit — execution layer з будь-яким execution environment, settlement у будь-якій ланцюзі (або без settlement взагалі). Максимальна гнучкість, мінімальна зрілість.
Data Availability Layer
Блоки повинні бути доступні для завантаження — інакше fraud proofs і state reconstruction неможливі. DA layer зберігає дані транзакцій (calldata або blobs).
Ethereum L1 (EIP-4844 blobs) — максимальна безпека, найвища вартість. Після EIP-4844: ~3–6 blobs на блок, кожен blob ~128KB, вартість blob gas відокремлена від execution gas. Blobs видаляються через ~18 днів, але commitment (KZG) залишається назавжди.
Celestia — спеціалізований DA layer. Data availability sampling (DAS): light nodes перевіряють доступність через випадкове семплювання, не завантажуючи весь блок. Вартість на порядки нижча ніж Ethereum blobs при порівняних security guarantees для більшості use cases.
EigenDA — DA layer поверх Ethereum через EigenLayer restaking. Економічна безпека від рестейкнутого ETH. Значно вища пропускна здатність ніж Ethereum L1 з вищими security гарантіями ніж Celestia (на сьогодні).
Avail — DA layer з data availability sampling, forkless upgrades. Гарна альтернатива Celestia.
Settlement Layer
Фіналізація: визначає, що є канонічним станом rollup. Обробляє withdrawals, вирішує спори.
Для більшості проектів — Ethereum mainnet через L1 bridge contract. Альтернатива для L3 — використовувати L2 як settlement layer (наприклад, Arbitrum One як settlement для Orbit chain).
Практична збірка: OP Stack + Celestia + Ethereum
Конкретна конфігурація, яку використовують у production.
Компоненти
[Users/Apps]
↓
[op-geth (execution)] ← кастомний EVM, ваші precompiles
↓
[op-node (rollup node)] ← derive chain state, communicate with L1
↓
[op-batcher] → [Celestia] ← публікує batch даних в Celestia
↓
[op-proposer] → [L1 Settlement Contract] ← публікує state roots на Ethereum
Настройка Celestia DA
// Celestia client для відправки blobs
import (
"github.com/celestiaorg/celestia-node/api/rpc/client"
"github.com/celestiaorg/celestia-openrpc/types/blob"
)
type CelestiaDA struct {
client *client.Client
namespace blob.Namespace
}
func (c *CelestiaDA) Submit(ctx context.Context, data []byte) (uint64, error) {
b, err := blob.NewBlob(0, c.namespace, data)
if err != nil {
return 0, fmt.Errorf("create blob: %w", err)
}
height, err := c.client.Blob.Submit(ctx, []*blob.Blob{b}, blob.DefaultGasPrice())
if err != nil {
return 0, fmt.Errorf("submit blob: %w", err)
}
return height, nil
}
func (c *CelestiaDA) Retrieve(ctx context.Context, height uint64) ([]byte, error) {
blobs, err := c.client.Blob.GetAll(ctx, height, []blob.Namespace{c.namespace})
if err != nil {
return nil, err
}
if len(blobs) == 0 {
return nil, ErrBlobNotFound
}
return blobs[0].Data, nil
}
Namespace — 29-байтовий ідентифікатор вашого rollup у Celestia. Потрібно зарезервувати унікальний namespace до запуску.
Конфігурація op-batcher для Celestia
OP Stack batcher не має нативної підтримки Celestia — потрібен кастомний DA provider через AltDA (Alternative DA) інтерфейс:
// Реалізація AltDA provider для Celestia
type CelestiaAltDA struct {
da *CelestiaDA
}
func (c *CelestiaAltDA) GetInput(ctx context.Context, commitment []byte) ([]byte, error) {
// Decode commitment → Celestia block height + namespace
height, err := decodeCommitment(commitment)
if err != nil {
return nil, err
}
return c.da.Retrieve(ctx, height)
}
func (c *CelestiaAltDA) SetInput(ctx context.Context, data []byte) ([]byte, error) {
height, err := c.da.Submit(ctx, data)
if err != nil {
return nil, err
}
return encodeCommitment(height), nil
}
У конфігурації op-batcher:
[da]
type = "celestia"
rpc = "http://celestia-light-node:26658"
auth_token = "${CELESTIA_AUTH_TOKEN}"
namespace = "0x0000000000000000000000000000000000yournamespace"
L1 Settlement контракти
На Ethereum деплоятся два контракти:
OptimismPortal — входна/вихідна точка для cross-domain сообщений і withdrawals. Обробляє challenge window для Optimistic.
L2OutputOracle — зберігає state roots, запропоновані proposer. Це те, від чого залежить finality withdrawals.
// Спрощена схема interaction
contract L2OutputOracle {
struct OutputProposal {
bytes32 outputRoot; // keccak256(state_root, msg_passer_storage_root, latest_block_hash)
uint128 timestamp;
uint128 l2BlockNumber;
}
OutputProposal[] public l2Outputs;
address public proposer;
uint256 public constant FINALIZATION_PERIOD = 7 days;
function proposeL2Output(
bytes32 _outputRoot,
uint256 _l2BlockNumber,
bytes32 _l1BlockHash,
uint256 _l1BlockNumber
) external payable {
require(msg.sender == proposer, "Not proposer");
// Верифікуємо що l1BlockHash відповідає _l1BlockNumber
require(blockhash(_l1BlockNumber) == _l1BlockHash, "Bad L1 block");
l2Outputs.push(OutputProposal({
outputRoot: _outputRoot,
timestamp: uint128(block.timestamp),
l2BlockNumber: uint128(_l2BlockNumber)
}));
}
}
Кастомізація execution layer
Custom precompiles
Precompiles — передкомпільовані контракти по фіксованих адресах з нативною реалізацією. Наприклад, додати BLS12-381 операції або кастомний хеш-алгоритм:
// У op-geth: додавання custom precompile
var CustomPrecompiles = map[common.Address]vm.PrecompiledContract{
common.HexToAddress("0x0000000000000000000000000000000000000100"): &blsG1Add{},
common.HexToAddress("0x0000000000000000000000000000000000000101"): &customHashFunction{},
}
type blsG1Add struct{}
func (c *blsG1Add) RequiredGas(input []byte) uint64 {
return 500 // фіксована вартість
}
func (c *blsG1Add) Run(input []byte) ([]byte, error) {
if len(input) != 128 {
return nil, errors.New("invalid input length")
}
// BLS G1 point addition
p1 := new(bls12381.G1Affine)
p2 := new(bls12381.G1Affine)
p1.Unmarshal(input[:64])
p2.Unmarshal(input[64:])
result := new(bls12381.G1Affine).Add(p1, p2)
return result.Marshal(), nil
}
Gas token кастомізація
OP Stack підтримує Custom Gas Token — native gas token, відмінний від ETH. Це дозволяє використовувати ваш ERC-20 токен як gas.
Обмеження: custom gas token повинен бути задеплоєн на L1, мати стандартний ERC-20 інтерфейс і не мати transfer fees (rebasing/fee-on-transfer токени не підтримуються).
Fee структура й sequencer revenue
User Transaction Fee = (base_fee + priority_fee) × gas_used [L2 execution cost]
+ L1 data fee [cost of DA]
Sequencer Revenue = collected fees - DA costs - L1 costs
При використанні Celestia замість Ethereum для DA, L1 data fee знижується на 90–95% для більшості транзакцій. Це головний економічний аргумент.
Моніторинг модульного стеку
Мніторити потрібно всі три шари незалежно:
# Ключові метрики
execution_layer:
- l2_block_time_seconds # повинен бути стабільний
- sequencer_queue_depth # навантаження на sequencer
- tx_pool_size # розмір mempool
da_layer:
- celestia_blob_submission_latency_ms
- celestia_blob_submission_cost_utia # вартість в TIA
- da_submission_failures_total
settlement_layer:
- l1_output_proposal_delay_blocks # proposer не відстає?
- l1_finalization_pending_count # withdrawals які чекають на finalization
- l1_gas_price_gwei # вартість proposer transactions
Alerting: якщо DA submission починає відставати від block production — це блокуюча проблема. Без DA блоки не верифіковні, а challengers не можуть отримати дані для fraud proof.
Декомпозиція за терміном
| Фаза | Зміст | Срок |
|---|---|---|
| Design | Вибір стеку, namespace, токеномика, bridge design | 2–3 тиж |
| Core setup | op-stack deployment, L1 contracts, genesis | 3–4 тиж |
| DA integration | Celestia/EigenDA connector, batcher config | 2–3 тиж |
| Testnet | Публічний тестнет, bridge testing, stress test | 3–4 тиж |
| Security | Аудит bridge контрактів, fault proof testing | 4–6 тиж |
| Mainnet | Деплой, sequencer ops, monitoring | 2–3 тиж |
Критичний шлях — аудит bridge контрактів. Bridge — це де живуть реальні гроші користувачів, і саме тут більшість L2 знайшла критичні уязвимості. Економити на аудиті bridge не можна.
Итого: 16–23 тижні від старту до mainnet. Команда: 2–3 backend інженера з досвідом Go, 1 Solidity розробник, DevOps/інфраструктурний інженер.







