Pull to refresh

Дебажим chaincode в Hyperledger Fabric

Reading time 4 min
Views 13K

image

Добрый день, дорогие хаброжители и в особенности те, которые в той или иной мере интересуются блокчейном. Так уж получилось, что придя работать java-разработчиком в одну компанию, мне пришлось заниматься проектами, использующими блокчейн.


Про сам блокчейн, его особенности и различные реализации в интернете, и на Хабре в частности, можно найти тонну информации. Но чем глубже вопросы, тем меньше на них ответов. В официальной документации fabric очень мало информации про дебаг, а та которая есть заключается в том, что бы просто залогировать весь код и смотреть, что же пошло не так. Русскоязычные разработчики IBM ответили точно так же. Так что в данной статье будет освещена одна из наших бывших проблем, связанная с дебагом чейнкода в одном из проектов Hyperledger, а именно — Fabric (v0.6).



Чейнкод в fabric это ничто иное, как привычный нам смарт-контракт. Чейнкод может быть написан на Go, Java и, в скором будущем, на JavaScript. В статье рассматривается реализация чейнкода на Go, но думаю данный подход подойдёт и для Java-реализаций.


Немного предисловия о том, как используется чейнкод со стороны ноды:


  1. Нода получает запрос на деплой → ищет docker-контейнер → если не находит, то создаёт новый docker-контейнер с чейнкодом внутри, если же находит, то использует его
  2. После создания контейнера, в нём запускается исполняющий файл чейнкода, который подключается по gRPC к ноде и начинает слушать её указания
  3. Когда на ноду поступает какой-либо Invoke/Query-запрос, она просто посылает подключенным исполняющим файлам команды, они обрабатывают их и отсылают результат обратно

Соответственно, изначально мы искали способ, как обмануть ноду, что бы она не искала контейнер, но успехом это не увенчалось. Быстренькое чтение docker-compose файлов выявило интересный параметр — CORE_CHAINCODE_MODE, с помощью которого можно заставить ноду не создавать и не искать контейнеры, а просто довериться окружающей среде.


Итак, в качестве среды будет использованы:


  • 1 нода в качестве membersrvc
  • 1 нода в качестве validation peer (далее VP)
  • Intellij Idea с плагином для Go

Как поднимать среду расписывать не буду, так как документации по разворачиванию очень много, стоит лишь отметить некоторые особенности:


Так как используется всего 1 VP, то алгоритм консенсуса PBFT, который используется по-умолчанию, нам не подходит. Для этого в конфигурации (docker-compose файле) необходимо добавить параметр
CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=noops.


Теперь необходимо указать, что наша среда должна быть запущена в dev-моде, для этого служит необходимо установить параметр CORE_CHAINCODE_MODE=dev.


Также необходимо прокинуть порты 7050 (используется для REST API ноды) и 7051 (используется для gRPC подключения к ноде).


На этом необходимые параметры заканчиваются, остальное можете настроить по своему усмотрению.


В качестве примера будет использоваться пример чейнкода из официального репозитория Hyperledger, а именно — map.


Теперь перейдём к настройкам среды. Для этого необходимо установить 2 параметра, а именно:


  1. Указать переменную Environment — CORE_CHAINCODE_ID_NAME=mapCC
  2. Указать аргумент запуска -peer.address=ip:gRpcPort

Вместо "mapCC" можно указать любое имя чейнкода. После этого нужно запустить чейнкод через метод main в режиме дебага. IDE должна вывести следующую информацию:


13:36:57.675 [shim] DEBU: Peer address: 192.168.1.1:7051
13:36:57.676 [shim] DEBU: os.Args returns: [C:\Users\vasya\AppData\Local\Temp\Build map.go and rungo -peer.address=192.168.1.1:7051]
13:36:57.701 [shim] DEBU: Registering… sending REGISTER
13:36:57.702 [shim] DEBU: []Received message REGISTERED from shim
13:36:57.702 [shim] DEBU: []Handling ChaincodeMessage of type: REGISTERED(state:created)
13:36:57.702 [shim] DEBU: Received REGISTERED, ready for invocations

Далее необходимо послать команду деплоя на ноду.


curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" -d "{
\"jsonrpc\": \"2.0\",
\"method\": \"deploy\",
\"params\": {
\"type\": 1,
\"chaincodeID\":{
\"name\":\"mapCC\"
},
\"ctorMsg\": {
\"function\":\"init\"
},
\"secureContext\": \"test_user0\"
},
\"id\": 1
}" ip:RESTPort/chaincode

Тут же в IDE появится информация


13:37:12.038 [shim] DEBU: [mapCCId2]Received message INIT from shim
13:37:12.038 [shim] DEBU: [mapCCId2]Handling ChaincodeMessage of type: INIT(state:established)
13:37:12.038 [shim] DEBU: Entered state init
13:37:12.038 [shim] DEBU: [mapCCId2]Received INIT, initializing chaincode
13:37:12.038 [shim] DEBU: [mapCCId2]Init succeeded. Sending COMPLETED
13:37:12.038 [shim] DEBU: [mapCCId2]Move state message COMPLETED
13:37:12.038 [shim] DEBU: [mapCCId2]Handling ChaincodeMessage of type: COMPLETED(state:init)
13:37:12.038 [shim] DEBU: [mapCCId2]send state message COMPLETED

После этого можно ставить breakpoint в любом нужном месте и дебажиться, отправляя Invoke/Query запросы. Думаю о них писать уже не надо, всё практически аналогично Init-запросам.


На этом статья подходит к концу, руками и ногами просьба сильно не бить, я всего лишь джуниор и это моя первая статься на Хабре и надеюсь она поможет кому-нибудь так как подобной статьи я не нашёл нигде.

Tags:
Hubs:
+8
Comments 2
Comments Comments 2

Articles