Содержание статьи:
- Требования
- 1. Начало
- 2.Изменение состояния базы данных (Mutating Global DB State)
- Бонус для клиентов
Цель этого гайда - разобрать технологические составляющие блокчейна на практике. Для этого рассмотрим кейс разработки собственного блокчейна с нуля.
Мы расскажем вам историю разработчика, который хотел произвести революцию в своем баре, внедрив блокчейн для платежей.
И хотя у блокчейна много применений, в основном сейчас его используют для проведения транзакций. Причина этому проста - банки все еще работают на неэффективной инфраструктуре, которой больше 40 лет.
В этом гайде вы узнаете:
1. Как разработать Go проект на своем компьютере без опыта работы с Golang.
2. Как создать и распределить блокчейн токены.
3. Как разработать базу данных CLI на языке Golang с нуля.
4. Как сделать свою базу данных неизменной при помощи криптографической хеш функции.
5. Как мало прав есть у пользователей самых популярных приложений.
Начнем с истории разработки распределенного реестра. Нашего главного героя зовут Андрей. Днем он владелец бара, а ночью - разработчик ПО. Он живет в небольшом городе на востоке Словакии под названием Ба?рдеёв.
Андрей устал:
1. Программировать старомодные PHP/Java/Javascript приложения.
2. Забывать сколько клиенты должны за неоплаченные шоты.
3. Тратить время на пересчет монет, купюр и выдачу сдачи.
4. Выдавать пластиковые монетки, по которым посетители могут играть в настольный футбол и прочие игры.
Андрей хотел бы:
1. Иметь понятную и прозрачную финансовую историю активности бара и продаж, благодаря которой он бы мог легко соблюдать все регулирующие нормы.
2. Превратить свой бар в автономную, децентрализованную и безопасную среду, которая бы приносила прибыль и ему и его клиентам.
Его цель - написать простую программу, которая бы следила за балансами его клиентов в виртуальной форме. Андрей пишет:
Каждый новый клиент будет давать мне наличку. Я буду перечислять на их электронный счет определенное количество своих цифровых токенов (монет, криптовалют). Эти токены будут представлять собой единицу расчета в баре и вне его стен. Клиенты будут использовать эти токены для оплаты всех услуг бара - напитков, еды, настольных игр. Кроме того, эти монеты можно будет одалживать своим друзьям.
Он продолжает:
Это даст мне возможность генерировать прибыль для моих посетителей. Клиенты моего бара будут держать токены и иметь права акционеров. Они смогут голосовать за цену напитков, часы работы, новые фичи, дизайн бара, распределение прибыли и т.д. Я назову свои токены The Blockchain Bar (TBB).
Теперь, когда мы знаем цель Андрея, можем приступать к разбору.
Требования
Для полного понимания рекомендуется 2+ года опыта программирования на Java/PHP/Javascript или на другом языке, похожем на Golang.
Посоветуем также пройти официальный курс A Tour Of Go, чтобы ознакомиться с синтаксисом языка и основными концепциями (это займет около 20 минут).
Андрей занимался базами данных SQL в 90х. Он знает как сделать и оптимизировать продвинутое решение. Для создания базы он выбрал простой но надежный файл JSON.
1. Начало
Разберем процесс создания блокчейна пошагово.
Андрей генерирует 1 миллион токенов.
У каждого блокчейна есть генезис-блок, который распределяет первые токены ранним участникам.
Начинается все просто - с обыкновенного genesis.json.
Андрей создает файл ./database/genesis.json, в котором определяет что на его блокчейне будет 1 миллион токенов и все они будут принадлежать ему.
Дальше он занимается ценообразованием - присуждает каждому токену стоимость в евро, долларах или другой валюте.
Он также решает, что должен получать 100 токенов в день за поддержание базы данных.
2.Изменение состояния базы данных (Mutating Global DB State)
Наш герой готов принимать токены в своем баре. К сожалению, никто к нему не заходит, поэтому он заказывает три рюмки водки для себя и записывает эту сделку в бумажную базу данных:
Для того, чтобы постоянно не пересчитывать балансы клиентов, андрей создаёт файл ./database/state.json.
База данных выглядит следующим образом:
{ "balances": { "andrej": 1000700 }}
Бонус для клиентов
Чтобы привлечь новых клиентов Андрей объявляет об акции - он предоставит 100% бонус на покупку токенов TBB в следующие 24 часа.
Маркетинговый ход сработал. Его первый клиент под ником BabaYaga купил TBB на €1000 и, чтобы отметить событие, потратил один токен на рюмку водки.
Транзакция, записанная на бумаге:
База данных выглядит следующим образом:
{ "balances": { "andrej": 998801, "babayaga": 1999 }
Андрей решил немного отдохнуть, поиграть в видеоигры и почистить свой жесткий диск от старых фотографий. К несчастью, он случайно нажал Enter когда вводил команду удаления в терминале sudo rm -rf /
Все его файлы, в том числе Genesis.json и State.json его бара исчезли. Поскольку наш герой имеет опыт в разработке, он не растерялся. Хотя у него не было бэкапа, у него было кое-что получше - листик бумаги, на котором записаны все транзакции в его базе данных. Теперь ему нужно только заново провести все транзакции и база данных восстановится.
Он решает улучшить свою базу данных MVP архитектурой, построенной на событиях. (Event-based architecture). Каждое действие а баре, вроде единичной покупки напитка, должно быть записано в базу данных блокчейна.
Каждый клиент будет представлен в базе данных при помощи структуры Account.
type Account string
Каждая транзакция будет иметь четыре характеристики: откуда, куда, размер и данные.
type Tx struct { From Account `json:"from"` To Account `json:"to"` Value uint `json:"value"` Data string `json:"data"`}func (t Tx) IsReward() bool { return t.Data == "reward"}
Генезисная база данных останется файлом JSON:
{ "genesis_time": "2019-03-18T00:00:00.000000000Z", "chain_id": "the-blockchain-bar-ledger", "balances": { "andrej": 1000000 }}
Все транзакции, ранее записанные на куске бумаги, будут хранится в локальной текстовой базе данных tx.db:
{"from":"andrej","to":"andrej","value":3,"data":""}{"from":"andrej","to":"andrej","value":700,"data":"reward"}{"from":"andrej","to":"babayaga","value":2000,"data":""}{"from":"andrej","to":"andrej","value":100,"data":"reward"}{"from":"babayaga","to":"andrej","value":1,"data":""}
Ключевым компонентом базы данных, отвечающим за бизнес-логику будет структура State:
type State struct { Balances map[Account]uint txMempool []Tx dbFile *os.File}
Структура State будет знать балансы всех пользователей, а также адресата, отправителя, и сумму транзакций. State считывает начальные балансы пользователей с файла genesis.json.
После этого изначальные балансы обновляются, заново проигрывая все события из базы данных tx.db.
Компонент State отвечает за:
- Добавление транзакций в мемпул
- Подтверждение транзакций
- Сохранение транзакйий на диск
- Подсчет балансов пользователей
Добавление транзакций в мемпул:
func (s *State) Add(tx Tx) error { if err := s.apply(tx); err != nil { return err } s.txMempool = append(s.txMempool, tx) return nil}
Подтверждение транзакций:
func (s *State) apply(tx Tx) error { if tx.IsReward() { s.Balances[tx.To] += tx.Value return nil } if tx.Value > s.Balances[tx.From] { return fmt.Errorf("insufficient balance") } s.Balances[tx.From] -= tx.Value s.Balances[tx.To] += tx.Value return nil}
Сохранение транзакций на диск:
func (s *State) Persist() error { // Make a copy of mempool because the s.txMempool will be modified // in the loop below mempool := make([]Tx, len(s.txMempool)) copy(mempool, s.txMempool) for i := 0; i < len(mempool); i++ { txJson, err := json.Marshal(mempool[i]) if err != nil { return err } if _, err = s.dbFile.Write(append(txJson, '\n')); err != nil { return err } // Remove the TX written to a file from the mempool s.txMempool = s.txMempool[1:] } return nil
Продолжение следует. В следующих частях мы рассмотрим процесс создания интерфейса командной строки, основные свойства хэш функции и как работает неизменность блокчейна на практике.