Как создать свой блокчейн с нуля при помощи Go? Часть 3

Содержание статьи:

  • 4. Человеческая жадность
  • 5. Зачем нам нужен блокчейн?
  • Как создать неизменную базу данных?
  • 6. Неизменность при помощи функции хэш
  • Время попрактиковаться
  • Заключение

Цель этого гайда - разобрать технологические составляющие блокчейна на практике. Для этого рассмотрим кейс разработки собственного блокчейна с нуля.

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

Клиент бара BabaYaga слишком увлекся инвестированием. Он забыла, что подходит срок оплаты аренды, и у нее не осталось свободных средств. Баба Яга звонит хозяину квартиры Цезарю.

Баба Яга: Привет, Цезарь. Мне очень жаль, но у меня нет денег заплатить за квартиру в этом месяце.

Цезарь: Это еще почему?

Баба Яга: Ну, ICO Blockchain Bar предлагали огромные бонусы и я купил токенов на $2000 всего за $1000. Это была отличная сделка!

Цезарь: Что за дичь? Что за ICO? Что за токены? Заплати мне нормальными деньгами.

Баба Яга: Давай так - я дам тебе 1000 TBB токенов, которые стоят $1000. Ты можешь потратить их в баре и расплачиваться за выпивку! Я позвоню владельцу бара, и он быстренько переведет тебе токены.

Цезарь: Ну ладно, я их приму.

Андрей проводит транзакцию, но решает снять 50 TBB комиссии за потраченное время. Ему-то самому этого, конечно, не хочется, но акционеры бара требуют приносить прибыль как можно быстрее. 

“Баба Яга все равно не заметит крошечной комиссии”, - подумал Андрей. В конце-концов, доступ к базе данных есть только у него.

 // Rent payment?tbb tx add --from=babayaga --to=caesar --value=1000// hidden fee charge? tbb tx add --from=babayaga --to=andrej --value=50// new reward for another day of maintaining the DB? tbb tx add --from=andrej --to=andrej --value=100 --data=reward

Баба Яга заходит в бар отмечать свой день рождения.

Баба Яга: Привет, Андрей! Сегодня мой день рождения! Давай свою самую дорогую бутылку!

Андрей: С днем рождения! Вот, прошу - водка Crystal Head. Но тебе нужно докупить еще один TBB токен. Бутылка стоит 950 TBB, а у тебя на балансе всего 949.

Баба Яга: В смысле?? У меня на балансе должно быть 999 TBB!

Андрей: Перевод денег Цезарю стоил тебе 50 токенов.

Баба Яга: Это недопустимо! Я бы никогда не согласился на такую комиссию. Так нельзя делать, Андрей. Я доверил твоей системе, а ты меня кинул. Так не пойдет.

Андрей: Ладно, послушай. Ты мой самый частый клиент, и я не хотел с тебя стягивать деньги, но меня заставили акционеры. Давай я перепишу систему и сделаю ее полностью прозрачной и децентрализованной. Если все смогут взаимодействовать с баром без моего посредничества, это должно повысить уровень доверия!

1. Заказ напитков будет занимать секунды, а не минуты

2. Пользователи, которые забыли кошельки дома, могут одалживать токены друг у друга.

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

4. База данных будет неизменна, никто не сможет внести правки в нее.

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

Баба Яга: Звучит, конечно, хорошо. Ты уверен, что это выполнимо?

Андрей: Думаю да.

Баба Яга: Ну тогда иди и занимайся своими блокчейнами.

Если Андрей хочет выяснить как создать неизменную базу данных, сначала ему нужно узнать почему остальные базы данных изначально изменяемы. Он решил изучить базу данных MySQL:

В MySQL DB любой, у кого есть доступ, может внести изменение в таблицу:

UPDATE user_balance SET balance = balance + 100 WHERE id > 1

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

Процесс хэширования - это преобразование данных произвольного размера в короткую строку определенного размера. Любое изменение изначальных данных приведет к созданию нового хэша.

package mainimport ("crypto/sha256""fmt")func main() {balancesHash := sha256.Sum256([]byte("| 1 | Andrej | 99895 |"))fmt.Printf("%x\n", balancesHash)// Output: 6a04bd8e2...f70a3902374f21e089ae7cc3b200751// Change balance from 99895 -> 99896balancesHashDiff := sha256.Sum256([]byte("| 1 | Andrej | 99896 |"))fmt.Printf("%x\n", balancesHashDiff)// Output: d04279207...ec6d280f6c7b3e2285758030292d5e1}

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

1. Детерминированная - одинаковое сообщение всегда будет иметь одинаковый хэш

2. Небольшое изменение в сообщении полностью изменяет хэш

3. Имея в наличии хэш невозможно сгенерировать изначальное сообщение, только перепробовав все возможные варианты

4. Невозможно найти два разных сообщения с одинаковым хэшем.

Андрей модифицирует функцию Persist(), что бы она делала Snapshot хэша каждый раз, когда сохраняется новая транзакция.

type Snapshot [32]byte

Snapshot производится новой функцией sha256 secure hashing

func (s *State) doSnapshot() error {   // Re-read the whole file from the first byte   _, err := s.dbFile.Seek(0, 0)   if err != nil {      return err   }   txsData, err := ioutil.ReadAll(s.dbFile)   if err != nil {      return err   }   s.snapshot = sha256.Sum256(txsData)   return nil

Когда новая транзакция записывается в файл tx.db , Persist() хэширует весь файл и возвращает 32-байтный хэш-отпечаток.

С этого момента каждый клиент может 100% конфиденциально и безопасно получить нужный набор данных при помощи нужного снимка.

1. Запустите команду tbb balances list и проверьте совпадают ли балансы.

2. Уберите две последние строчки из ./database/tx.db и проверьте балансы заново.

3. Выплатим награду Андрею за два дня работы:

Транзакция 1

? tbb tx add --from=andrej --to=andrej --value=100 --data=rewardPersisting new TX to disk:       {"from":"andrej","to":"andrej","value":100,"data":"reward"}New DB Snapshot: ff2470c7043f5a34169b5dd38921ba6825b03b3facb83e426TX successfully persisted to the ledger.

Транзакция 2

? tbb tx add --from=andrej --to=andrej --value=100 --data=rewardPersisting new TX to disk:       {"from":"andrej","to":"andrej","value":100,"data":"reward"}       New DB Snapshot: 7d4a360f468b837b662816bcdc52c1869f99327d53ab4a9caTX successfully persisted to the ledger.

4. Запустите команду tbb balances list и убедитесь, что все снимки хэшей совпадают с изначальными.

? tbb balances listAccount balances at 7d4a360f465d...| id | name     | balance || -- | -------- | ------- || 1  | Andrej   | 999251  || 2  | BabaYaga | 949     | | 3  | Caesar   | 1000    |

Готово!

Так как криптографическая хэш функция sha256 производит одинаковую строку при одинаковых входных данных вы можете повторить эти шаги на своем компьютере и сгенерировать такую же базу данных и такие же хэши!

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

Изменения в базе данных называются транзакциями. Транзакции - это события внутри системы, которые записываются на блокчейн.

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