Реестр

Целевая аудитория: архитекторы, разработчики приложений и умных контрактов, администраторы

Реестр является ключевой концепцией Hyperledger Fabric. Реестр хранит важную фактическую информацию о бизнес-объектах, включая текущие значения атрибутов объектов, а также историю транзакций, которые привели к текущим значениям.

В этом разделе:

Что такое реестр?

Реестр отражает текущее состояние дел в виде журнала транзакций. Самые ранние европейские и китайские реестры появились почти 1000 лет назад, а 4000 лет у шумеров назад были реестры в камне. Но давайте начнем с более современного примера!

Все видели цифры собственного банковского счета. Самое важное в нем — это доступный баланс, то есть количество денег, которое можно потратить в текущий момент. Чтобы узнать, как образовался текущий баланс, нужно посмотреть операции прихода и расхода, которые его определили. Это и есть реальный пример реестра — текущее состояние (банковский баланс) и набор последовательных операций (приход и расход), которые его определяют. Hyperledger Fabric решает эти две задачи — представление текущего набора состояний реестра и хранение истории транзакций, которые определили эти состояния.

Реестры, факты и состояния

Реестр не хранит бизнес-объекты непосредственно — он хранит факты об этих объектах. Фраза «бизнес-объект хранится в реестре» на самом деле означает непрерывный процесс записи фактов о текущем состоянии объекта и фактов об истории транзакций, которые привели к текущему состоянию. В современном мире цифровых технологий может казаться, что мы смотрим на объект, а не на факты об объекте. В случае с цифровым объектом, скорее всего он хранится во внешнем хранилище данных. При этом хранящиеся в реестре факты позволяют определить его местонахождение вместе с другой ключевой информацией.

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

Рассмотрим подробнее структуру реестра Hyperledger Fabric.

Реестр

В Hyperledger Fabric реестр состоит из двух различных, хотя и связанных, частей — глобального состояния и блокчейна. Обе части представляют собой набор фактов о множестве бизнес-объектов.

Первая часть реестра - глобальное состояние - это база данных, в которой хранятся текущие значения множества состояний реестра. Глобальное состояние упрощает прямой доступ к текущему значению состояния, устраняя необходимость вычислений с использованием всего журнала транзакций. Состояния реестра по умолчанию выражаются в виде пар ключ-значение и далее мы расскажем о гибкости Hyperledger Fabric в этом отношении. Глобальное состояние часто меняется, когда состояния создаются, обновляются и удаляются.

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

ledger.ledger Реестр L состоит из блокчейна B и глобального состояния W, при этом блокчейн B определяет глобальное состояние W. Или, если сказать по-другому, глобальное состояние W строится на основе блокчейна B.

Для ясности, следует понимать, что сеть Hyperledger Fabric содержит один логический реестр. На самом деле в сети поддерживается нескольких копий реестра, согласованность которых обеспечивается процессом, называемым консенсус. Часто к такому типу реестра применяют термин технология распределенного реестра (DLT), что означает логически уникальный реестр, имеющий множество согласованных копий, распределенных по сети.

Далее рассмотрим глобальное состояние и структуру данных блокчейна более подробно.

Глобальное состояние

Глобальное состояние содержит текущее значение атрибутов бизнес-объекта в форме уникального состояния реестра. Такой способ удобен, так как код приложений обычно запрашивает текущее значение объекта. Просмотр всей цепочки блоков для вычисления текущего значения объекта является затруднительным. Поэтому текущее значение берется непосредственно из глобального состояния.

ledger.worldstate Глобальное состояние реестра, содержащее два состояния. Первое состояние описывается следующей парой «ключ-значение»: key=CAR1 и value=Audi. Во втором состоянии значение имеет более сложную форму: key=CAR2 and value={model:BMW, color=red, owner=Jane}. Оба состояния имеют версию 0.

Состояние реестра хранит набор фактов о конкретном бизнес-объекте. В приведенном примере показаны состояния реестра для двух автомобилей CAR1 и CAR2, каждый из которых описывается парой «ключ-значение». Приложения может вызывать умный контракт с помощью простых функций API реестра для получения (get), записи (put) и удаления (delete) состояний. Следует отметить, что значение состояния может быть простым (Audi…) или составным (type:BMW…). К глобальному состоянию часто обращаются для получения объектов с определенными атрибутами, например, чтобы найти все красные BMW.

Глобальное состояние реализовано в виде базы данных. Это рационально, поскольку база данных предоставляет большой набор функций для эффективного хранения и извлечения состояний. Далее мы рассмотрим, каким образом можно использовать различные базы данных глобального состояния в Hyperledger Fabric для поддержки разных типов значений состояния и моделей доступа, требуемых приложениями, например, при сложных запросов.

Приложения отправляют транзакции, которые содержат изменения глобального состояния, и эти транзакции в конечном итоге записываются в блокчейн реестра. Приложения изолированы от реализации механизма консенсуса с помощью SDK Hyperledger Fabric. Приложения только вызывают умные контракты и получают уведомление о добавлении транзакции (подтверждена или не подтверждена) в блокчейн. Ключевой особенностью Hyperledger Fabric является то, что обновление глобального состояния осуществляется только с помощью транзакций, подписанных требуемым множеством одобряющих организаций. Соответственно, глобальное состояние не изменяется, если транзакция не подписана достаточным количеством одобряющих узлов. По следующим ссылкам приведена дополнительная информация о разработке приложений и о том, как приложения используют умные контракты.

Можно заметить, что состояние имеет номер версии, и на схеме выше состояния CAR1 и CAR2 имеют нулевые версии. Номера версий предназначены для внутреннего использования Hyperledger Fabric и увеличивается при каждом изменении состояния. Номер версии проверяется каждый раз при обновлении состояния для подтверждения, что текущее состояние соответствуют версии на момент одобрения. Это гарантирует ожидаемое изменение глобального состояния и отсутствие параллельных обновлений.

Следует добавить, что глобальное состояние является пустым при создании реестра. Поскольку любая подтвержденная транзакция, которая изменяет глобальное состояние, записывается в блокчейн, глобальное состояние может быть в любой момент повторно воссоздано из блокчейна. Этот принцип отлично подходит, например, для автоматического создания глобального состояния при добавлении однорангового узла. Более того, в случае сбоя в работе однорангового узла, глобальное состояние может быть восстановлено после перезапуска однорангового узла перед принятием транзакций.

Блокчейн

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

Структура блокчейна выглядит как последовательный журнал связанных блоков, где каждый блок содержит последовательность транзакций, а каждая транзакция содержит запрос или обновление глобального состояния. Подробности механизма упорядочивания транзакций описаны здесь. Важно отметить, что последовательность блоков и последовательность транзакций внутри блоков определяется при создании блоков компонентом Hyperledger Fabric, который называется служба упорядочения.

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

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

Рассмотрим структуру блокчейна более подробно.

ledger.blockchain Блокчейн B, содержащий блоки B0, B1, B2, B3. B0 — это первый блок блокчейна, или первичный блок.

На приведенной выше схеме блок B2 содержит данные блока D2, которые содержат все его транзакции: T5, T6, T7.

Наиболее важно то, что блок B2 включает заголовок блока H2, который содержит криптографическую хеш-сумму всех транзакций в D2, а также хеш заголовка H1. Таким образом, блоки неразрывно и неизменно связаны друг с другом, что и отражает термин блокчейн (т.е. цепочка блоков).

Наконец, как видно на схеме, первый блок блокчейна называется первичным блоком (genesis). Это исходная точка реестра, однако этот блок не содержит пользовательских транзакций. Он содержит транзакцию конфигурации, содержащую исходное состояние сетевого канала (на схеме не показано). Более подробно первичный блок рассматривается в разделе про блокчейн-сеть и каналы.

Блоки

Рассмотрим структуру блока. Блок состоит из трех разделов

  • Заголовок блока

    Этот раздел состоит из трех полей, которые заполняются при создании блока.

    • Номер блока: целое число, начинающееся с 0 (первичный блок) и увеличивающееся на 1 для каждого нового блока, добавляемого в блокчейн.
    • Хеш-сумма текущего блока: хеш-сумма всех транзакций, содержащихся в текущем блоке.
    • Хеш-сумма заголовка предыдущего блока.

    Значения этих полей вычисляются системой путем криптографического хеширования данных блока. Эти значения гарантируют неразрывную связь каждого блока со своим соседом, образуя неизменяемый реестр.

    ledger.blocks Подробное представление заголовка блока. Заголовок H2 блока B2 состоит из блока номер 2, хеш-суммы CH2 данных текущего блока D2 и хеш-суммы заголовка предыдущего блока H1.

  • Данные блока

    Этот раздел содержит упорядоченный список транзакций. Он записывается при создании блока службой упорядочения. Транзакции имеют сложную, но понятную структуру, которая будет рассмотрена позже.

  • Метаданные блока

    Этот раздел содержит сертификат и подпись создателя блока, которые используются для проверки блока узлами сети. Впоследствии подтверждающий этот блок узел добавляет флаг подтверждения для каждой транзакции в битовую карту, которая содержится в метаданных блока, а также хеш-сумму совокупных обновлений состояния до этого блока включительно для возможности обнаружения «вилки» (fork) состояний. В отличие от полей данных блока и заголовка, этот раздел не используется для вычисления хеш-суммы блока.

Транзакции

Как мы видели, транзакции содержат изменения в глобальном состоянии. Далее рассмотрим подробную структуру данных блока, в которой эти транзакции содержатся.

ledger.transaction Структура транзакции. Транзакция T4 в данных D1 блока B1 состоит из заголовка транзакции H4, подписи транзакции S4, запроса на транзакцию P4, ответа на транзакцию R4 и списка одобрений E4.

В приведенном выше примере присутствуют следующие поля:

  • Заголовок

    Этот раздел (H4 на схеме) содержит некоторые важные метаданные транзакции, например, имя соответствующего чейнкода и его версию.

  • Подпись

    Этот раздел (S4 на схеме) содержит криптографическую подпись, созданную клиентским приложением. Это поле используется для проверки того, что содержимое транзакции не было изменено, поскольку для его генерации требуется закрытый ключ приложения.

  • Предложение

    Это поле (P4 на схеме) содержит входные параметры, предоставляемые приложением для умного контракта, который создает предлагаемое обновление реестра. При исполнении умного контракта в этом предложении содержится набор входных параметров, которые в сочетании с текущим глобальным состоянием определяют новое глобальное состояние.

  • Ответ

    Этот раздел (R4 на схеме) содержит значения глобального состояния до и после в виде набора чтения-записи (RW-набор). Этот набор — результат выполнения умного контракта и, в случае успешного подтверждения транзакции, он применится к реестру для обновления глобального состояния.

  • Одобрения

    Как показано на схеме (E4), это список подписанных ответов на транзакции от всех организаций, необходимых для удовлетворения политики одобрения. Можно заметить наличие нескольких одобрений, хотя транзакция содержит только один ответ. Это происходит потому, что каждое одобрение по сути содержит конкретный ответ соответствующей организации на транзакцию. Поэтому нет необходимости включать ответы на транзакции, которые не соответствует достаточному количеству одобрений, поскольку они будут отклонены как неподтвержденные без возможности обновить глобальное состояние.

Мы рассмотрели основные поля транзакции. Есть и другие, однако упомянутых достаточно, чтобы иметь хорошее представление о структуре данных реестра.

Параметры базы данных глобального состояния

Глобальное состояние физически реализовано в виде базы данных для простого и эффективного хранения и поиска состояний реестра. Как уже говорилось, состояния реестра могут иметь простые или составные значения, и поэтому реализация базы данных глобального состояния может изменяться для эффективного представления таких значений. На данный момент база данных глобального состояния может быть реализована на основе LevelDB и CouchDB.

LevelDB используется по умолчанию и подходит для случаев, когда состояния реестра — это простые пары «ключ-значение». База данных LevelDB совмещена с одноранговым узлом — она встроена в тот же процесс операционной системы.

CouchDB лучше подходит для случаев, когда состояния реестра имеют структуру документов JSON, поскольку CouchDB поддерживает расширенные запросы и обновление более сложных типов данных, которые часто встречаются в транзакциях бизнес-процессов. С точки зрения реализации CouchDB использует отдельный процесс операционной системы, однако количество экземпляров CouchDB соответствует количеству одноранговых узлов, как и в случае LevelDB. Все эти подробности скрыты от умных контрактов. Дополнительная информация о CouchDB представлена в этом разделе.

Базы данных LevelDB и CouchDB указывают на важный аспект модульности Hyperledger Fabric. База данных глобальных состояний может быть реляционным хранилищем, хранилищем на основе графов или временной базой данных. Это позволяет эффективно получать доступ ко множеству типов состояний реестра в Hyperledger Fabric и решать множество различных типов проблем.

Пример реестра: fabcar

В конце этой статьи рассмотрим пример реестра. Его можно создать, запустив пример приложения Fabcar.

Пример приложения Fabcar создает набор из 10 автомобилей с уникальными значениями цвета, производителя, модели и владельца. На схеме ниже показано как выглядит реестр после добавления первых четырех машин.

ledger.transaction Реестр L включает глобальное состояние W и блокчейн B. Глобальное состояние W содержит четыре состояния с ключами CAR0, CAR1, CAR2 и CAR3. Блокчейн B содержит два блока — 0 и 1. Блок 1 содержит четыре транзакции: T1, T2, T3, T4.

Можно увидеть, что глобальное состояние содержит записи, соответствующие автомобилям CAR0, CAR1, CAR2 и CAR3. Значение CAR0 указывает на то, что это синий Toyota Prius, в настоящее время принадлежащий Tomoko, и можно видеть аналогичные состояния и значения для других автомобилей. Кроме этого можно отметить, что все состояния автомобилей имеют номер версии 0, т.е. начальный номер версии, так как они не обновлялись с момента создания.

Как уже упоминалось, блокчейн состоит из двух блоков. Блок 0 является первичным блоком, хотя он не содержит транзакций, связанных с автомобилями. Блок 1 в свою очередь содержит транзакции T1, T2, T3, T4, и они соответствуют транзакциям, которые создали начальные состояния для автомобилей CAR0–CAR3 в глобальном состоянии. И, наконец, блок 1 связан с блоком 0.

На схеме не показаны другие поля в блоках или транзакциях, в частности заголовки и хеш-суммы. Полное описание этих полей можно найти в специальном справочном разделе документации. В нем приводится подробное описание примера блока с транзакциями. А в рамках этой статьи мы получили твердое концептуальное понимание принципа устройства реестра Hyperledger Fabric.

Пространства имен

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

Блокчейн не имеет пространства имен. Он содержит транзакции из множества различных пространств имен умных контрактов.

Дополнительная информация о пространствах имен чейнкодов представлена в этой статье.

Далее рассмотрим, как концепция пространства имен применяется в каналах Hyperledger Fabric.

Каналы

В Hyperledger Fabric каждый канал имеет полностью отдельный реестр. Это означает полностью отдельный блокчейн и отдельные глобальные состояния, включая пространства имен. Приложения и умные контракты могут взаимодействовать между каналами, чтобы иметь возможность получить доступ к данным реестров.

Дополнительная информация о взаимодействии реестров с каналами приведена в этой статье.

Далее

Для более глубокого понимания процесса исполнения транзакций, контроля параллелизма и базы данных глобального состояния ознакомьтесь с разделами: выполнение транзакций, семантика наборов чтения-записи и база данных состояний на основе CouchDB.