- Оригинальный адрес:Code your own blockchain in less than 200 lines of Go!
- Оригинальный автор:Coral Health
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Starrier
- Корректор:ALVINYEH,github.com/SergeyChang
Если вы читаете эту статью не в первый раз, пожалуйста, прочтите часть 2 -здесь!
Этот учебник адаптирован из этой превосходной статьи о написании базовых блокчейнов на JavaScript.статья. Мы перенесли его на Go и добавили некоторые дополнительные преимущества, такие как просмотр вашей цепочки блоков в веб-браузере. Если у вас есть какие-либо вопросы по поводу приведенных ниже руководств, обязательно присоединяйтесь к нам.Telegram. Не стесняйтесь задавать нам любые вопросы!
Примеры данных в этом руководстве будут основаны на вашем сердцебиении в состоянии покоя. В конце концов, мы медицинская компания :-) Ради интереса запишите свою одну минутучастота пульса(ударов в минуту) и запомните это значение.
Почти каждый разработчик в мире слышал о блокчейне, но большинство до сих пор не знает, как он работает. Они могут знать о Биткойне только из-за него или, может быть, потому, что слышали о смарт-контрактах или чем-то подобном. Этот пост пытается демистифицировать блокчейны, помогая вам написать свой собственный простой блокчейн на Go, используя менее 200 строк кода! К концу этого руководства вы сможете писать и запускать собственный блокчейн локально, а также просматривать его в веб-браузере.
Есть ли лучший способ узнать о блокчейне, чем создать свой собственный?
что ты сможешь сделать
- Создайте свой собственный блокчейн
- Узнайте, как хеширование поддерживает целостность блокчейна
- Узнайте, как добавлять новые блоки
- Посмотрите, как разрешаются конфликты, когда несколько узлов генерируют блоки
- Просмотр блокчейна в веб-браузере
- написать новый блок
- Получите основы блокчейна, чтобы вы могли решить, куда пойдет ваше путешествие!
что ты не можешь сделать
Чтобы упростить эту статью, мы не будем рассматривать более сложные концепции консенсуса, такие как Proof of Work и Proof of Stake. Для того, чтобы вы могли просматривать свой блокчейн и добавление блоков, мы смоделируем сетевые взаимодействия, но глубина веб-трансляции как статьи будет сохранена.
Давайте начнем!
Готов к работе
Теперь, когда мы решили программировать на Go, мы предполагаем, что у вас уже есть некоторый опыт работы с Go, вУстановитьА после настройки Go нам также необходимо получить следующие пакеты:
go get github.com/davecgh/go-spew/spew
SpewПозволяет нам просматривать чисто отформатированные в консолиstructs
иslices
, ты заслуживаешь это.
go get github.com/gorilla/mux
Gorilla/muxЭто обычный пакет для написания обработки веб-программ. Мы будем использовать его.
go get github.com/joho/godotenv
Gotdotenvпозволяет нам читать из корневого каталога.env
файл, поэтому вам не нужно жестко кодировать такие вещи, как HTTP-порты. Нам это тоже нужно.
Создаем в корневом каталоге.env
файл, определяющий порт для обслуживания http-запросов. Просто добавьте строку в файл:
ADDR=8080
Создайтеmain.go
документ. Отныне все будет записано в этот файл и закодировано менее чем в 200 кодах.
Импортировать
Это то, что нам нужно импортировать и объявление пакета, мы пишем их вmain.go
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"log"
"net/http"
"os"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
)
модель данных
Мы определим каждый блок, который составляет блокчейнstruct
. Не волнуйтесь, через минуту мы объясним, что означают все эти поля.
type Block struct {
Index int
Timestamp string
BPM int
Hash string
PrevHash string
}
каждыйBlock
Оба содержат данные, которые будут записаны в блокчейн, и представляют каждую ситуацию, когда вы получаете свой пульс (помните, когда вы делали это в начале статьи?).
-
Index
где данные записываются в блокчейн -
Timestamp
заключается в том, чтобы автоматически определять, когда записывать данные -
BPM
ударов в минуту, что является вашей частотой пульса -
Hash
это идентификатор SHA256, представляющий эту запись данных -
PrevHash
это идентификатор SHA256 предыдущей записи в цепочке
Мы также моделируем сам блокчейн, это простоBlock
серединаslice
:
var Blockchain []Block
Так как же хеширование вписывается в блоки и блокчейны? Мы используем хеш-таблицы для определения и поддержания правильного порядка блоков. гарантируя, что каждыйBlock
серединаPrevHash
с переднейBlock
в блокеHash
То же самое, мы знаем правильный порядок блоков, составляющих цепочку.
Хэширование и генерация новых блоков
Так зачем нам хеширование? Есть две основные причины, по которым мы хэшируем данные:
- Чтобы сэкономить место. Хэш получается из всех данных в блоке. В нашем примере у нас есть только несколько точек данных, но, допустим, у нас есть данные из сотен, тысяч или миллионов предыдущих фрагментов. хеш-данные в одну строку SHA256 илихешировать эти хеш-таблицынамного эффективнее, чем многократное копирование всех данных в предыдущем блоке.
- Защитите целостность блокчейна. Сохраняя предыдущий хэш, как мы это сделали на диаграмме выше, мы можем гарантировать, что блоки в блокчейне расположены в правильном порядке. Если злоумышленник попытается манипулировать данными (например, изменить частоту сердечных сокращений, чтобы определить цену страхования жизни), хэш быстро изменится, цепочка «разорвется», и все узнают о злонамеренной цепочке и перестанут доверять ей.
Напишем функцию, которая принимаетBlock
data и создайте хэш SHA256 i .
func calculateHash(block Block) string {
record := string(block.Index) + block.Timestamp + string(block.BPM) + block.PrevHash
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hex.EncodeToString(hashed)
}
этоcalculateHash
функция будетBlock
изIndex
,Timestamp
,BPM
, мы предоставляем блокиPrevHash
Цепочка в качестве параметра и возвращает хэш SHA256 в виде строки. Теперь мы можем использовать новыйgenerateBlock
для создания нового блока, содержащего все необходимые нам элементы. Нам нужно предоставить блок перед ним, чтобы мы могли получить его хэш и частоту пульса в BPM. Не беспокойтесь о входящихBPM int
параметр. Мы обсудим это позже.
func generateBlock(oldBlock Block, BPM int) (Block, error) {
var newBlock Block
t := time.Now()
newBlock.Index = oldBlock.Index + 1
newBlock.Timestamp = t.String()
newBlock.BPM = BPM
newBlock.PrevHash = oldBlock.Hash
newBlock.Hash = calculateHash(newBlock)
return newBlock, nil
}
Обратите внимание на текущее использование времениtime.Now()
автоматически записывается в блок. Также обратите внимание, что наш предыдущийcalculateHash
Функция вызывается. Скопируйте из хеша предыдущего блока вPrevHash
.Index
Увеличение от индекса предыдущего блока.
проверка блока
Нам нужно написать некоторые функции, чтобы гарантировать, что эти блоки не были подделаны. Так же проходим техосмотрIndex
чтобы убедиться, что они увеличиваются, как ожидалось. Мы также проверим, чтобы убедиться, что нашиPrevHash
с предыдущим блокомHash
такой же. Наконец, мы хотим снова запустить текущий блок с помощьюcalculateHash
функция для перепроверки хэша текущего блока. Давайте напишемisBlockValid
функция, которая делает все это и возвращаетbool
. Если он проходит все наши проверки, он возвращаетtrue
:
func isBlockValid(newBlock, oldBlock Block) bool {
if oldBlock.Index+1 != newBlock.Index {
return false
}
if oldBlock.Hash != newBlock.PrevHash {
return false
}
if calculateHash(newBlock) != newBlock.Hash {
return false
}
return true
}
Если у нас есть проблема, когда оба узла экосистемы блокчейна добавляют блоки в свою цепочку, и мы оба получаем их. Какой из них мы выбираем в качестве источника истины? Выбираем самую длинную цепочку. Это классическая проблема блокчейна, которая не имеет ничего общего со злодеями.
Два значимых узла могут просто иметь разную длину цепочки, поэтому, естественно, более длинный узел будет самым новым и будет иметь самые новые блоки. Итак, давайте удостоверимся, что новая цепочка, которую мы принимаем, длиннее, чем наша существующая цепочка. Если это так, мы можем перезаписать нашу цепочку новой цепочкой с новыми блоками.
Для этого мы просто сравниваем длины цепочек:
func replaceChain(newBlocks []Block) {
if len(newBlocks) > len(Blockchain) {
Blockchain = newBlocks
}
}
Если вы зашли так далеко, поощряйте себя! По сути, мы написали внутренности блокчейна с различными необходимыми нам функциями.
Теперь нам нужен удобный способ просмотра нашего блокчейна и записи в него, в идеале мы можем показать его нашим друзьям в веб-браузере!
веб сервер
Мы предполагаем, что вы уже знакомы с тем, как работают веб-серверы, и имеете некоторый опыт их подключения к Go. Теперь мы проведем вас через этот процесс.
Мы будем использовать ваш ранее загруженныйGorilla/muxпакет, чтобы сделать тяжелую работу для нас.
мы позвоним позжеrun
Функция для создания сервера.
func run() error {
mux := makeMuxRouter()
httpAddr := os.Getenv("ADDR")
log.Println("Listening on ", os.Getenv("ADDR"))
s := &http.Server{
Addr: ":" + httpAddr,
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
if err := s.ListenAndServe(); err != nil {
return err
}
return nil
}
Обратите внимание, что выбранный нами порт относится к ранее созданному порту..env
документ. Мы используемlog.Println
Отправьте себе живое консольное сообщение, чтобы запустить наш сервер. Мы немного настроили оружие, а затемListenAndServe
настроить. Довольно стандартный Go.
Теперь нам нужно написатьmakeMuxRouter
функция, которая будет определять все обработчики. Для просмотра и записи в нашу цепочку блоков в браузере нам нужны только два маршрута, и мы сделаем их простыми. Если мы отправимGET
запроситьlocalhost
, мы рассмотрим блокчейн. Если мы отправимPOST
запрос, мы можем написать.
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
return muxRouter
}
это нашеGET
процессор.
func handleGetBlockchain(w http.ResponseWriter, r *http.Request) {
bytes, err := json.MarshalIndent(Blockchain, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, string(bytes))
}
Нам просто нужно записать полную цепочку блоков в формате JSON, доступ к которой можно получить с помощьюlocalhost:8080
Просмотр в любом браузере. мы в.env
документ будетADDR
Для переменной установлено значение 8080, если вы измените ее, убедитесь, что вы указали правильный порт.
нашPOST
Запрос немного сложный (их не много). Во-первых, нам нужен новыйMessage
struct
. Позже мы объясним, зачем нам это нужно.
type Message struct {
BPM int
}
Ниже приведен код для написания обработчика нового блока. Мы приглашаем вас посмотреть его снова после того, как вы его прочтете.
func handleWriteBlock(w http.ResponseWriter, r *http.Request) {
var m Message
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&m); err != nil {
respondWithJSON(w, r, http.StatusBadRequest, r.Body)
return
}
defer r.Body.Close()
newBlock, err := generateBlock(Blockchain[len(Blockchain)-1], m.BPM)
if err != nil {
respondWithJSON(w, r, http.StatusInternalServerError, m)
return
}
if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) {
newBlockchain := append(Blockchain, newBlock)
replaceChain(newBlockchain)
spew.Dump(Blockchain)
}
respondWithJSON(w, r, http.StatusCreated, newBlock)
}
использовать автономныйMessage
Причина структуры — получение тела запроса JSON POST, которое мы будем использовать для записи новых блоков. Это позволяет нам просто отправить запрос POST со следующим телом, и наш обработчик заполнит остальную часть блока за нас:
{"BPM":50}
50
является примером частоты пульса в единицах минут. Измените частоту пульса на целочисленное значение.
Расшифровка тела запроса вvar m Message
структуру, передав предыдущий блок и передав новую частоту пульса ранее записанномуgenerateBlock
Функция для создания нового блока. Это все, что нужно функции для создания нового блока. Используем ранее созданныйisBlockValid
функция, быстрая проверка, чтобы убедиться, что новый блок в порядке.
некоторые примечания
-
_spew.Dump_
— это удобная функция, которая выводит нашу структуру на консоль. Это полезно для отладки. -
Для тестирования запросов POST нам нравится использовать Postman.
curl
Отлично работает, если вы не можете выйти из терминала.
Когда наш POST-запрос завершается успешно или неудачно, мы хотим получать соответствующие уведомления. Мы использовали небольшую функцию-оболочкуrespondWithJSON
Давай, дай нам знать, что случилось. Помните, в Go никогда не игнорируйте их.обращаться с ними изящно.
func respondWithJSON(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
response, err := json.MarshalIndent(payload, "", " ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("HTTP 500: Internal Server Error"))
return
}
w.WriteHeader(code)
w.Write(response)
}
Почти готово!
Давайте свяжем все различные функции блокчейна, веб-обработчики и веб-серверы в коротком, ясномmain
В функции:
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal(err)
}
go func() {
t := time.Now()
genesisBlock := Block{0, t.String(), 0, "", ""}
spew.Dump(genesisBlock)
Blockchain = append(Blockchain, genesisBlock)
}()
log.Fatal(run())
}
Как это происходит?
-
godotenv.Load()
позволяет нам начать с корневого каталога.env
Переменные, такие как номера портов, считываются в файле, поэтому нам не нужно жестко кодировать их во всем приложении (отвратительно!). -
genesisBlock
даmain
Самая важная часть функции. Нам нужно предоставить нашей цепочке блоков начальный блок, иначе новый блок не сможет сравнить свой предыдущий хэш ни с чем, потому что предыдущий хеш не существует. - Мы изолировали начальный блок в его собственную процедуру Go, чтобы мы могли отделить проблемы от нашей логики блокчейна и логики веб-сервера. Но он просто работает более элегантно без подпрограмм Go.
Очень хороший! Мы сделали!
Вот полный код:
А теперь поговорим о чем-нибудь интересном. Давай попробуем :-)
использоватьgo run main.go
Запустите приложение из терминала
В терминале мы видим, что веб-сервер запущен и работает, и получаем распечатку нашего начального блока.
Теперь используйте свой номер порта для доступаlocalhost
, 8080 для нас. Как и ожидалось, мы видим тот же начальный блок.
Теперь давайте отправим несколько запросов POST для добавления фрагментов. Используя Postman, мы добавим несколько новых блоков с разными BPM.
Обновим браузер. Вуаля, теперь мы видим все новые блоки в цепочке с новым блокомPrevHash
со старыми блокамиHash
совпало, как мы и ожидали!
Следующий шаг
Поздравляем! Вы просто пишете свой собственный блокчейн с правильным хешированием и проверкой блоков. Теперь вы сможете взять под контроль свое путешествие по блокчейну и изучить более сложные темы, такие как Proof of Work, Proof of Stake, смарт-контракты, Dapps, сайдчейны и другие.
Что не обсуждается в этом руководстве, так это то, как использовать Proof of Work для добычи новых блоков. Это будет чистое руководство, но существует большое количество блокчейнов без механизма проверки работоспособности. Кроме того, трансляции в настоящее время имитируются путем записи и просмотра блокчейна на веб-сервере. В этом руководстве нет компонентов P2P.
Если вы хотите, чтобы мы добавили такие вещи, как подтверждение работы и отношений, обязательно опубликуйте в нашемTelegramрасскажите нам и следите за нашимиTwitter! Это лучший способ связи с нами. Задавайте нам вопросы, оставляйте отзывы и предлагайте новые уроки. Мы хотели бы услышать от вас.
По многочисленным просьбам мы добавили продолжение этого урока! Проверь их!
- блокчейн сеть.
- Напишите свой собственный алгоритм майнинга блокчейна!
- Узнайте, как использовать ipfs для хранения данных в блокчейне.
- Напишите собственное доказательство алгоритма пня!
Чтобы узнать больше о здоровье кораллов и о том, как мы используем блокчейн для продвижения персонализированных исследований в области медицины и лечения, посетите нашВеб-сайт.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.