Перейти к основному содержимому

Философия и архитектура

Весь hlf-core стоит на нескольких принципах, и если понять их, остальное читается уже как следствие. Поэтому прежде чем переходить к отдельным пакетам, стоит разобрать саму идею.

Принцип 1. Одна точка входа и конверт команды​

В обычном chaincode каждая операция — это отдельная функция контракта, и добавление новой операции меняет его интерфейс. Мы пошли иначе: у контракта одна функция (transportFabricExecute), а любая операция упаковывается в конверт команды. Что именно вызвано — определяет поле name в конверте, а не имя функции.

Отсюда два следствия. Во-первых, клиентский код пользуется единым API — transport.send(...) и transport.sendListen(...), одинаково и для блокчейна, и для обычных сервисов, потому что модель команд общая (она приходит из @ts-core). Во-вторых, чтение и запись разделены флагом isReadonly: readonly-команды идут через evaluate, без записи в ledger, а остальные — через submit, с полным циклом endorsement.

Принцип 2. Подпись на уровне приложения​

Fabric аутентифицирует организацию — идентичность gateway и MSP, но не конечного пользователя. В enterprise этого мало: нам нужно знать, кто именно инициировал операцию, и защититься от повторного воспроизведения транзакции. Поэтому hlf-core кладёт в конверт подпись приложения (userId и signature) и nonce, который строго возрастает и хранится в состоянии. Так поверх стандартной модели Fabric появляется сквозная идентификация пользователя и защита от replay.

Принцип 3. ORM поверх key-value​

Состояние Fabric — это key-value с диапазонными запросами по префиксу. hlf-core даёт поверх него ORM-подобный слой: сущности, связи parent-child через пару прямого и обратного ключей, пагинацию, автоматическую сериализацию и валидацию. Ключи строятся через StateKey так, чтобы вторичный поиск по левому префиксу составного ключа оставался предсказуемым, а не превращался в случайный обход соседних записей.

Слои​

TOKENScoincoin-chaincodeTRANSPORTtransporttransport-commontransport-chaincodeNETWORK / ORMapichaincodeFOUNDATIONcommonBASE@ts-core/common
hlf-core layers: from the platform-neutral common to the domain pair coin.

Логика разбиения простая. В common вынесено всё платформо-нейтральное — то, что нужно и клиенту, и chaincode. Дальше идёт ветвление на две среды: клиентскую (api, затем transport) и среду chaincode (chaincode, затем transport-chaincode). А transport-common держит их протокол синхронным — один и тот же код на обеих сторонах не даёт конвертам «разъехаться». Пара coin и coin-chaincode повторяет ту же симметрию уже на предметном уровне, поверх транспорта.

Путь типичной команды​

Чтобы принципы сложились в целое, проследим команду от клиента до chaincode и обратно.

Clientcreates the command, takes a nonce and signs itEnveloperequest packaging, clear() of defaultstransportFabricExecuteevaluate (readonly) or submitChaincode: intakesignature, public key and nonce checksHandlerbusiness logic, StateProxy — atomic commitResponsereadonly — immediately; submit — from the block by requestId
Command path: a single entry point, application signature, response from the block.
  1. Клиент создаёт команду и зовёт transport.sendListen(cmd, {userId, signature}). Перед этим nonce запрашивается readonly-командой, увеличивается и подписывается.
  2. Собирается конверт запроса, и из него выкидываются значения по умолчанию — чтобы не раздувать ledger лишними данными.
  3. Конверт уходит через единственную функцию контракта; по isReadonly выбирается evaluate или submit.
  4. На стороне chaincode конверт парсится, проверяется подпись — алгоритм, публичный ключ, nonce, криптографическая верификация, и команда диспетчеризуется обработчику по полю name.
  5. Обработчик выполняет бизнес-логику: пишет и читает состояние через менеджеры, изменения копятся в StateProxy и фиксируются атомарно, а события отправляются через stub.dispatch.
  6. Для readonly-команды ответ возвращается сразу. Для записи он попадает в блок — клиент разбирает блок и сопоставляет ответ с исходной командой по requestId.

Подробнее о проверке подписи — в разделе «Безопасность», а о самом протоколе — в @hlf-core/transport.