@hlf-core/transport-chaincode
Это зеркальная половина клиентского транспорта — всё то, что происходит на стороне chaincode, когда к нему приходит команда. Пакет берёт на себя рутину приёма и проверки, оставляя разработчику только бизнес-логику: аутентификацию, валидацию и работу с состоянием он делает сам.
Точка входа — TransportFabricChaincode, который реализует ChaincodeInterface из fabric-shim
(его Init и Invoke) и запускается привычным shim.start. Всю содержательную работу он
делегирует приёмнику TransportFabricChaincodeReceiver. Приёмник парсит входящий конверт,
проверяет подпись и диспетчеризует команду зарегистрированному по имени обработчику. Сама проверка
подписи — это цепочка: алгоритм из списка cryptoManagers, авторизация публичного ключа, nonce и
криптографическая верификация, и каждое звено может команду отклонить. Подробно эта цепочка
разобрана в разделе «Безопасность».
Доступ к состоянию внутри обработчика идёт через TransportFabricStub — обёртку над ChaincodeStub,
которая реализует IStub и несёт user, requestId и transaction. А за
атомарность отвечает StateProxy: он не пишет в ledger сразу, а копит изменения в памяти —
toPut и toRemove, и фиксирует их единым commit. Чтение при этом сначала заглядывает в
накопленный кэш, так что внутри одной транзакции мы всегда видим собственные, ещё не
зафиксированные изменения.
Для batch-режима есть TransportFabricChaincodeReceiverBatch — он принимает несколько команд и
исполняет их одной транзакцией, под отдельной подписью пакета. А TransportFabricSeededChaincode
решает отдельную задачу — инициализацию состояния начальными данными при первом запуске контракта.
export class MyChaincode extends TransportFabricChaincode<void> {
constructor(logger: ILogger) {
const transport = new TransportFabricChaincodeReceiver({
cryptoManagers: [{algorithm: 'secp256k1', publicKey: '...'}],
nonSignedCommands: ['healthCheck'],
});
super(logger, transport);
}
public get name(): string {
return 'MyChaincode';
}
}
shim.start(new MyChaincode(logger));
Коды ошибок — по подписи, nonce и batch — определены здесь же, так что по коду ответа всегда
видно, на каком именно звене команда была отклонена. Nonce, напомню, хранится по ключу
→${userId}~nonce и обязан строго возрастать, а readonly-команды его не трогают.