Learning Platform
Глоссарий Troubleshooting
Урок 04.05 · 15 мин
Продвинутый
Fan-outFan-inParallel MessagesScatter-GatherAggregation

Параллельные сообщения: Fan-out / Fan-in

Fan-out: один → много

Контракт отправляет одинаковые или разные сообщения нескольким получателям одновременно:

Fan-out Pattern
Master Contract
Worker 1
Worker 2
Worker N

Use Cases

СценарийОписание
AirdropMaster → N wallet contracts: “зачислить 100 tokens”
NotificationEvent contract → N subscriber contracts: “event happened”
GovernanceProposal → N voter contracts: “голосуйте”
NFT mintingCollection → N item contracts: deploy

Design Considerations

Fan-out Gas Calculation:
Total gas = N × (compute_per_worker + fwd_fee) + master_compute

Пример: airdrop на 1000 wallets
= 1000 × (0.01 TON + 0.005 TON) + 0.01 TON
= 15.01 TON  (!)

Optimization: batch sends per transaction (max ~255 messages per tx)
WARNING

Лимит: ~255 сообщений за транзакцию

TVM ограничивает количество outbound messages в одной транзакции. Для больших fan-out (>255 получателей) нужен chain of batch sends: Master отправляет первые 255 + сообщение самому себе “продолжить с 256-го”.

Fan-in: много → один

Несколько контрактов отправляют результаты одному aggregator:

Fan-in Pattern
Worker 1
Worker 2
Worker N
Aggregator

Проблема: когда все ответили?

Aggregator не знает заранее, когда все workers ответят. Нужен counter pattern:

// Aggregator state
self.expected_responses = N;
self.received_responses = 0;
self.results = {};

recv_internal(msg) {
  if (op == op::worker_result) {
    self.results[msg.worker_id] = msg.result;
    self.received_responses += 1;
    
    if (self.received_responses == self.expected_responses) {
      // Все ответили — финализация
      finalize(self.results);
      self.state = STATE_IDLE;
    }
  }
}

Design Problem: что если worker не ответил?

Timeout pattern:
1. При fan-out сохранить deadline
2. Если received < expected И deadline прошёл → 
   finalize с partial results ИЛИ abort + refund

Scatter-Gather: fan-out + fan-in

Комбинация: отправить запросы → собрать ответы → агрегировать:

Scatter-Gather: Oracle Price Aggregation

Master → Oracle_1: "get ETH price"
Master → Oracle_2: "get ETH price"  
Master → Oracle_3: "get ETH price"

Oracle_1 → Master: "$2,500"
Oracle_2 → Master: "$2,505"
Oracle_3 → Master: "$2,498"

Master: median(2500, 2505, 2498) = $2,500 → use as price

Design для Scatter-Gather

ПараметрПодход
QuorumЖдать 2/3 ответов (не все — один может быть offline)
TimeoutDeadline для каждого раунда
Outlier rejectionОтбросить ответы, отличающиеся > X% от медианы
GasMaster платит за все fan-out сообщения

Practical Guidelines

1. Минимизируйте fan-out

Каждое сообщение = gas. 1000 fan-out messages = 15+ TON. Спросите: можно ли pull вместо push?

[NO] Push (дорого): Master → 10,000 wallets: "your balance updated"
[OK] Pull (дёшево): Wallets → Master.get_balance(): бесплатный get-method

2. Batch processing для больших fan-out

Batch pattern:
Tx 1: send messages 0-254 + self-message("continue from 255")
Tx 2: send messages 255-509 + self-message("continue from 510")
...
Tx N: send messages (N-1)*255 ... last

3. Используйте counter + timeout

Для fan-in всегда используйте:

  • Counter для отслеживания полноты
  • Timeout для graceful degradation
  • Partial results вместо all-or-nothing
Проверка знанийKnowledge check
ОтветAnswer

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 2. Контракт Master хочет отправить airdrop на 2000 кошельков. TVM ограничивает ~255 outbound messages на транзакцию. Как спроектировать?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5