[Перевод] Напишите свой собственный алгоритм майнинга блокчейна на Go!

Go алгоритм Программа перевода самородков биткойн блокчейн
[Перевод] Напишите свой собственный алгоритм майнинга блокчейна на Go!

Если у вас есть какие-либо вопросы или предложения по приведенным ниже руководствам, присоединяйтесь к нам. Telegram Группа сообщений, вы можете спросить нас все, что хотите спросить!

В связи с недавними пожарами на майнинге биткойнов и эфириума легко задаться вопросом, почему происходит вся эта суета. Для новичков в этой области они услышат некоторые сумасшедшиеистория: Люди заполняют склады графическими процессорами и каждый месяц зарабатывают криптовалюту на миллионы долларов. Что такое майнинг электронной валюты? Как это работает? Как мне попробовать написать свой алгоритм майнинга?

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

Что такое майнинг электронной валюты

Чтобы быть ценными, электронные деньги должны иметь определенный дефицит. Если кто-то может производить столько биткойнов, сколько хочет, в любое время, биткойны бесполезны как валюта. (Подождите, разве этим не занимается Федеральная резервная система?пощечина) Алгоритм Биткойн будет выдавать некоторое количество биткойнов выигравшему участнику сети каждые десять минут с максимальным запасом около 122 лет. Этот график выпуска также в определенной степени контролирует инфляцию, поскольку нормированное предложение не полностью высвобождается в самом начале. Распространение будет все медленнее и медленнее с течением времени.

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

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

Как работает майнинг?

Быстрый поиск в Google по запросу «как работает майнинг биткойнов?» даст вам много страниц ответов, объясняющих, что для майнинга биткойнов требуется узел (вы или ваш компьютер).решить сложную математическую задачу. Хотя технически это верно, просто называть это «математической» проблемой слишком легкомысленно и банально. Очень интересно понять внутреннюю работу майнинга. Чтобы узнать, как работает майнинг, нам сначала нужно понять алгоритмы шифрования и хэши.

Краткое введение в хэш-шифрование

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

Давайте рассмотрим пример SHA-256, популярного алгоритма шифрования. этохэш-сайтПозволяет легко вычислять хэши SHA-256. Давайте хешируем «Hello world», чтобы посмотреть, что мы получим:

Попробуйте хешировать «Hello world» несколько раз. Каждый раз вы будете получать один и тот же хэш. При одних и тех же входных данных в программу повторные вычисления дадут один и тот же результат, который называется идемпотентностью.

Одним из основных свойств алгоритмов шифрования является то, что трудно вывести входное значение с помощью обратной операции, но легко проверить выходное значение (по входному значению). Например, с алгоритмом хеширования SHA-256, описанным выше, кто-то еще, применяя алгоритм хеширования SHA-256 к «Hello world», может легко убедиться, что он действительно выводит тот же результат хеширования, но хочет извлечь тот же хэш из It. получается, что "Hello world" будеточень сложно. Поэтому такие алгоритмы называютсяоднонаправленный.

Принятие биткойновДвойной SHA-256Алгоритм, этот алгоритм просто SHA-256опять такиХэш-значение SHA-256 применено к «Hello world». В этом уроке мы будем применять только алгоритм SHA-256.

добыча

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

Например, вернуться кхэш-сайтЗатем выполните хеш-операцию на «886». Он сгенерирует хеш-значение с префиксом из трех нулей.

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

Любой может легко проверить тот факт, что хеш-результат «886» начинается с трех нулей.доказал: Я проделал массу работы, чтобы протестировать и проверить множество комбинаций букв и цифр, чтобы получить этот результат. Итак, если я первым получу этот результат, я могу пройтиДоказыватьЯ действительно работал, чтобы получить биткойны — доказательство тому, что любой может легко проверить, что хэш «886» соответствует префиксу тройного нуля, как я утверждаю. Вот почему алгоритм консенсуса Биткойн называетсядоказательство работы.

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

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

Теперь вы знаете, что механизм консенсуса Биткойн гораздо интереснее, чем простое «решение математической задачи»!

Достаточно предыстории. Приступаем к программированию!

Теперь, когда у нас достаточно информации, давайте создадим собственную программу Биткойн, используя алгоритм консенсуса рабочей нагрузки. Мы собираемся написать его на Go, потому что мы используем его в Coral Health, и, честно говоря,Превосходно.

Прежде чем приступить к следующему шагу, я предлагаю читателям прочитать нашу предыдущую запись в блоге,Code your own blockchain in less than 200 lines of Go!.Это несложное требование, но в следующем примере мы будем грубыми. Если вам нужна дополнительная информация, вы можете обратиться к предыдущему блогу. Если вы знакомы с предыдущей статьей, сразу переходите к разделу «Доказательство работы» ниже.

структура

У нас будет сервис Go, мы просто поместим весь код в одинmain.goв файле. Этот файл будет содержать всю необходимую нам логику блокчейна (включая алгоритм проверки работоспособности) и включать все обработчики интерфейса REST. Данные блокчейна неизменны, нам нужно толькоGETа такжеPOSTпросить. Мы будем использовать браузер для отправкиGETзапрос на просмотр данных и использованиеPostmanотправлятьPOSTзапрос на новый блок (curlтак же работает).

упаковка

Начнем со стандартной операции импорта. обязательно используйтеgo getчтобы получить следующие пакеты

github.com/davecgh/go-spew/spewКрасиво распечатайте свой блокчейн в терминале

github.com/gorilla/muxПростой в использовании слой для подключения к вашим веб-сервисам

github.com/joho/godotenvв корневом каталоге.envПрочитайте переменные среды из файла

Давайте создадим его в корневом каталоге.envфайл, который просто содержит переменную среды, которую мы будем использовать через мгновение. существует.envНапишите строку в файле:ADDR=8080.

Сделайте объявление на пакете и в корневом каталогеmain.goИмпорт определения:

package main

import (
        "crypto/sha256"
        "encoding/hex"
        "encoding/json"
        "fmt"
        "io"
        "log"
        "net/http"
        "os"
        "strconv"
        "strings"
        "sync"
        "time"

        "github.com/davecgh/go-spew/spew"
        "github.com/gorilla/mux"
        "github.com/joho/godotenv"
)

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

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

некоторые основные зонды

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

const difficulty = 1

type Block struct {
        Index      int
        Timestamp  string
        BPM        int
        Hash       string
        PrevHash   string
        Difficulty int
        Nonce      string
}

var Blockchain []Block

type Message struct {
        BPM int
}

var mutex = &sync.Mutex{}

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

Blockявляется моделью данных каждого блока. не волнуйся не понимаюNonce, что мы объясним позже.

Blockchainэто серияBlock, представляющий полную цепочку.

Messageто, что мы используем в интерфейсе RESTPOSTЗапрос передан для создания новогоBlockИнформация.

Объявляем тот, который будет использоваться позжеmutexЧтобы предотвратить конкуренцию данных и гарантировать, что несколько блоков не будут генерироваться в один и тот же момент времени.

веб-сервис

Быстро подключимся к сетевому сервису. Создаватьrunфункцию, позже вmainПозвоните ему, чтобы поддержать службу. также нужноmakeMuxRouter()Объявите функцию обработчика маршрута в . Помните, нам нужно использовать толькоGETметод отслеживания содержимого блокчейна,POSTметод создания блока. Блокчейн нельзя изменить, поэтому нам не нужно изменять и удалять операции.

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
}

func makeMuxRouter() http.Handler {
        muxRouter := mux.NewRouter()
        muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
        muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
        return muxRouter
}

httpAddr := os.Getenv("ADDR")начнется с того, что мы только что создали.envВытащить порт из файла:8080. Мы можем получить доступ к браузеру[http://localhost:8080](http://localhost:8080)для доступа к приложению.

Давай напишемGETФункция обработчика для распечатки блокчейна в браузере. Мы также добавим простойrespondwithJSONфункция, она сообщит нам сообщение об ошибке в формате JSON, когда возникнет ошибка при вызове интерфейса.

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))
}

func respondWithJSON(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
        w.Header().Set("Content-Type", "application/json")
        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)
}

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

написать сейчасPOSTфункция обработчика. С помощью этой функции мы добавляем новые блоки. Мы используем Postman для отправкиPOSTЗапросите, отправьте тело JSON, например{“BPM”:60},прибыть[http://localhost:8080](http://localhost:8080), и укажите частоту сердечных сокращений, которую вы измерили ранее.

func handleWriteBlock(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        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()

        //ensure atomicity when creating new block
        mutex.Lock()
        newBlock := generateBlock(Blockchain[len(Blockchain)-1], m.BPM)
        mutex.Unlock()

        if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) {
                Blockchain = append(Blockchain, newBlock)
                spew.Dump(Blockchain)
        }   

        respondWithJSON(w, r, http.StatusCreated, newBlock)

}

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

Основные функции блокчейна

Перед запуском алгоритма проверки работоспособности давайте подключим основные функции блокчейна. мы добавимisBlockValidфункция, чтобы убедиться, что индекс увеличивается правильно, а текущий блокPrevHashи предыдущий блокHashзначение совпадает.

Мы также добавимcalculateHashфункция, которая генерирует то, что нам нужно использовать для созданияHashа такжеPrevHashхэш-значение. Это индекс, метка времени, BPM, хэш предыдущего блока иNonceХэш SHA-256 (мы объясним, что это такое позже).

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 calculateHash(block Block) string {
        record := strconv.Itoa(block.Index) + block.Timestamp + strconv.Itoa(block.BPM) + block.PrevHash + block.Nonce
        h := sha256.New()
        h.Write([]byte(record))
        hashed := h.Sum(nil)
        return hex.EncodeToString(hashed)
}

доказательство работы

Давайте посмотрим на алгоритм майнинга, или Proof of Work. Мы хотим убедиться, что алгоритм проверки работоспособности разрешает новый блокBlockдобавить в блокчейнblockchainЭто было сделано раньше. Начнем с простой функции, которая проверяет, соответствует ли хеш-значение, сгенерированное в алгоритме доказательства работы, установленным нами требованиям.

Наши требования следующие:

  • Хэш-значение, сгенерированное алгоритмом проверки работоспособности, должно начинаться с определенного количества нулей.
  • Количество нулей определяется константойdifficultyрешение, определяется в самом начале программы (в примере это 1)
  • Мы можем усложнить алгоритм проверки работоспособности, увеличив значение сложности

Выполните следующую функцию,isHashValid:

func isHashValid(hash string, difficulty int) bool {
        prefix := strings.Repeat("0", difficulty)
        return strings.HasPrefix(hash, prefix)
}

Иди в егоstringsУдобно в сумкеRepeatа такжеHasPrefixфункция. мы определяем переменныеprefixкак мы вdifficultyКопия определенных нулей. Затем мы проверяем значение хеша, чтобы увидеть, начинается ли оно с этих нулей, и если да, возвращаемTrueв противном случае вернутьсяFalse.

Теперь мы создаемgenerateBlockфункция.

func generateBlock(oldBlock Block, BPM int) Block {
        var newBlock Block

        t := time.Now()

        newBlock.Index = oldBlock.Index + 1
        newBlock.Timestamp = t.String()
        newBlock.BPM = BPM
        newBlock.PrevHash = oldBlock.Hash
        newBlock.Difficulty = difficulty

        for i := 0; ; i++ {
                hex := fmt.Sprintf("%x", i)
                newBlock.Nonce = hex
                if !isHashValid(calculateHash(newBlock), newBlock.Difficulty) {
                        fmt.Println(calculateHash(newBlock), " do more work!")
                        time.Sleep(time.Second)
                        continue
                } else {
                        fmt.Println(calculateHash(newBlock), " work done!")
                        newBlock.Hash = calculateHash(newBlock)
                        break
                }

        }
        return newBlock
}

мы создалиnewBlockи поместите хэш предыдущего блока вPrevHashсвойств, чтобы обеспечить непрерывность блокчейна. Значения других свойств просты:

  • IndexИнкрементный
  • Timestampэто строка, представляющая текущее время
  • BPMэто частота сердечных сокращений, которую вы записали ранее
  • DifficultyОн напрямую получается из константы в начале программы. Мы не будем использовать это свойство в этом руководстве, но если нам нужно выполнить дополнительную проверку и подтвердить, что значение сложности фиксировано для результата хеширования (т. е. результат хеширования начинается с N нулей, тогда значение сложности также должно быть равно N, иначе блокчейн сломается), это полезно.

forЦикл является критической частью этой функции. Рассмотрим подробнее, что здесь сделано:

  • мы установимNonceравныйiшестнадцатеричное представление . нам нужна функцияcalculateHashМетод добавления изменяющегося значения к сгенерированному хэшу, чтобы, если мы не получили ожидаемое количество нулевых префиксов, мы могли повторить попытку с новым значением.Значение изменения, которое мы добавляем к объединенной строке **calculateHash** под названием "Ононс"
  • В цикле мы используемiи Nonce на основе 0 для вычисления хеш-значения и проверки, начинается ли результат с константыdifficultyНачинается с определенного количества нулей. Если нет, мы начинаем следующий цикл с увеличивающимся Nonce и пытаемся снова.
  • Мы добавили задержку в одну секунду, чтобы имитировать время решения алгоритма проверки работоспособности.
  • Мы продолжаем цикл, пока не получим нулевой префикс, который нам нужен, что означает, что мы успешно завершили доказательство работы. Если и только после этого нашаBlockпройти черезhandleWriteBlockдобавлена ​​функция обработчикаblockchain.

Мы написали все функции, теперь давайте закончимmainфункция:

func main() {
        err := godotenv.Load()
        if err != nil {
                log.Fatal(err)
        }   

        go func() {
                t := time.Now()
                genesisBlock := Block{}
                genesisBlock = Block{0, t.String(), 0, calculateHash(genesisBlock), "", difficulty, ""} 
                spew.Dump(genesisBlock)

                mutex.Lock()
                Blockchain = append(Blockchain, genesisBlock)
                mutex.Unlock()
        }() 
        log.Fatal(run())

}

Мы используемgodotenv.Load()Функция загружает переменные среды, которые используются для доступа в браузере.:8080порт.

Процедура go создает блок генезиса, потому что он нужен нам как отправная точка для блокчейна.

Используем только что созданныйrun()Функция запускает сетевую службу.

законченный! Время запустить его!

Полный код здесь.

Давайте попробуем запустить этого ребенка!

использоватьgo run main.goчтобы запустить программу

а затем используйте браузер для доступа[http://localhost:8080](http://localhost:8080):

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

После отправки запроса,Посмотрите, что происходит в терминале. Вы увидите, что ваша машина занята созданием новых хэшей с увеличением значений Nonce, пока не найдет нужное значение с нулевым префиксом.

Когда алгоритм доказательства работы завершен, мы получаем полезныйwork done!сообщение, мы можем проверить хеш-значение, чтобы увидеть, действительно ли оно соответствует тому, что мы установили.difficultyначать с нуля. Это означает, что теоретически новый блок, в который мы пытались добавить информацию о BPM = 60, уже добавлен в наш блокчейн.

Обновим браузер и увидим:

удалось! Наш второй блок был добавлен после блока генезиса. Это означает, что мы успешноPOSTБлок отправляется в запросе, этот запрос запускает процесс майнинга, и он добавляется в цепочку блоков тогда и только тогда, когда алгоритм доказательства работы завершен.

следующий

отличный! То, что вы только что узнали, действительно важно. Алгоритм доказательства работы является основой Биткойн, Эфириум и многих других крупных блокчейн-платформ. То, что мы только что узнали, не тривиально; хотя в нашем примере мы использовали низкое значение сложности, увеличьте его до относительно большого значения.точноКак алгоритм проверки работоспособности блокчейна работает в производственной среде.

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

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

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

Хотите увидеть руководство по сравнению алгоритмов proof-of-work и proof-of-stake? Нашли ошибку в коде выше? Как то, что мы делаем? Ненавидите то, что мы делаем?

пройти через Присоединяйтесь к нашей группе в Telegram Поделитесь с нами вашими мыслями! Вы получите восторженный отклик от автора этого руководства и остальных членов команды Coral Health.

Чтобы узнать больше о Coral Health и о том, как мы используем блокчейн для улучшения исследований в области личной медицины, посетите нашВеб-сайт.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.