Создайте блокчейн на автономной машине на базе Golang.
Создайте блокчейн на автономной машине на базе Golang.

Создайте блокчейн на автономной машине на базе Golang.

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

Определение блокчейна

Структура данных блокчейна

Без лишних слов, Блокчейн на самом деле состоит из заголовка блока и блочного узла.

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

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

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

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

Что такое децентрализация?

Проще говоря,Традиционная архитектура B/S или C/S,К одному серверу или кластеру подключено множество клиентов.,А децентрализация означает,Сервер больше не управляет данными,Все данные существуют на каждом клиентском узле,наконец прошлоАлгоритм распределенного консенсусаДля достижения синхронизации блоков。

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

Для реализации кода здесь я использую Golang, поскольку Golang более удобен для последующего написания распределенного консенсуса, а его синтаксис проще, чем Java. Конечно, для его реализации можно также использовать C/C++.

Список блокчейнов

Язык кода:go
копировать
type BlockChain struct {
	Nodes    []*BlockNode `json:"nodes,omitempty"`    // массив узлов
	Version  string       `json:"version,omitempty"`  // номер версии
	TreeSize int64        `json:"treeSize,omitempty"` // Дерево Меркельразмер
}

в этой структуре,записал сериюизмассив указателей блоков,текущий Блокчейнизномер версии,ForTreeSize,специфическийиз Он используется для выражения Блокчейнсередина,Дерево Меркельизмаксимумразмер(Для хранения больших объемов данных и облегчения проверки)。

блочный узел

Язык кода:go
копировать
type BlockNode struct {
    // «Хеш-значение предыдущего узла»
    Prev"Hash      string            `json:"prev"Hash,omitempty"`
    // текущийузелизномер версии
    Version       string            `json:"version,omitempty"`
    // Временная метка создания текущего узла.
    Datestamp     long              `json:"datestamp,omitempty"`
    // Дерево в текущем узле Меркель
    RootTree      merkal.MerkalTree `json:"rootTree,omitempty"`
    // «Хеш-код» Меркель
    RootTreeCode  string            `json:"propertyCode,omitempty"`
    // Жетон, используемый для расчета сложности, расчета nonce Процесс ценности заключается в блокировании header Непрерывно вычисляйте хэш, пока не найдете хеш блока, который меньше target из nonce。(здесь Не делай слишком многоиз Разрабатывать,Это связано с майнингом)
    Nonce         string            `json:"nonce,omitempty"`
    // Текущий узел Дерево Меркельизразмер
    LocalTreeSize int64             `json:"LocalTreeSize,omitempty"`
}

Дерево Меркель

Давайте сначала поговорим о Дереве Меркельизструктура данныхкаково этоиз,Почему это можно сделать быстро?Блокчейнизпроверять。

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

Содержимое, хранящееся в каждом узле, представляет собой «хеш-значение» двух узлов, из которых оно поступает.

Дерево Меркельструктура данных
Дерево Меркельструктура данных
Язык кода:go
копировать
type MerkalTree struct {
    RootNode *MerkalNode `json:"rootNode,omitempty"`
    DataSet  *[]Message  `json:"dataSet,omitempty"`
    RootHash string      `json:"root"Hash,omitempty"`
}

Если проверка не удалась, мы рекурсивно следуем за корневым узлом для проверки. Временная сложность равна $log_n$.

Что, если информация об узле представляет собой нечетное число?

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

информационный прототип

Язык кода:go
копировать
package merkal

import (
	"encoding/json"
	"reflect"
	"time"
)

type Message struct {
	Title      string    `json:"title"`
	Text       string    `json:"text"`
	CreateTime time.Time `json:"createTime"`
}

func (this *Message) String() string {
	res, _ := json.Marshal(this)
	return string(res)
}

func (this *Message) Equals(other Message) bool {
	return reflect.DeepEqual(this, other)
}

Логика работы блокчейна

Операция хеширования — реализация глубокого хеширования.

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

Так как же этого добиться?

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

В Golang есть реализация глубокого копирования, но нам нужно ее зашифровать.

Мы можем имитировать способ, которым js реализует глубокое копирование, преобразовать его в строку json, а затем зашифровать строку json с помощью RSA, чтобы получить хэш-значение.

Для блочного узелизhashвычислить

Язык кода:go
копировать
type BlockChain struct {
	Nodes    []*BlockNode `json:"nodes,omitempty"`    // массив узлов
	Version  string       `json:"version,omitempty"`  // номер версии
	TreeSize int64        `json:"treeSize,omitempty"` // Дерево Меркельразмер
}

func (this *BlockChain) String() string {
	marshal, _ := json.Marshal(this)
	return string(marshal)
}
func NewBlockChain(treeSize int64) *BlockChain {
	return &BlockChain{TreeSize: treeSize, Version: "V1.0.0"}
}

func hash(node BlockNode) string {
	sum256 := sha256.Sum256([]byte(node.String()))
	return fmt.Sprintf("0x%x", sum256)
}

Здесь мы используем Sprintf для шестнадцатеричного вывода.

Хорошо, вот основная часть, дальше — более важная часть.

Дерево Меркельузелизhashвычислить

здесь,мы должны обратить внимание,Дерево Хэш Меркелиза и два вида структуры данных,Один из них — информационный прототип., другой - Дерево Меркельлист,Поэтому мы используем единый интерфейс для реализации,Затем мы трансформируем вниз

Язык кода:go
копировать
func hash(o1 common.Object, o2 common.Object) string {
	t1 := ""
	if o1 != nil {
		te, f := (o1).(*Message)
		if f {
			let := *te
			t1 = let.String()
			//fmt.Println(let, "=", t1)

		} else {
			let := *(o1).(*MerkalNode)
			t1 = let.String()
			//fmt.Println(let, "=", t1)
		}
	}
	t2 := ""
	if o2 != nil {
		te, f := (o2).(*Message)
		if f {
			let := *te
			t2 = let.String()
			//fmt.Println(let, "=", t2)

		} else {
			let := *(o2).(*MerkalNode)
			t2 = let.String()
			//fmt.Println(let, "=", t2)
		}
	}
	//fmt.Println("Хеширование", t1, t2)
	bytes := []byte(t1 + t2)
	sum256 := sha256.Sum256(bytes)
	return fmt.Sprintf("0x%x", string(sum256[:]))
}

Дерево Меркельизпроверять

Язык кода:go
копировать
func (this *MerkalTree) Valid(other MerkalTree) (*Message, bool) {
	if this.RootHash == other.RootHash {
		return nil, true
	}
	return this.RootNode.Valid(other.RootNode, this.DataSet, other.DataSet)
}

func (this *MerkalNode) Valid(other *MerkalNode, oldData *[]Message, newData *[]Message) (*Message, bool) {
	if this.Equals(other) {
		return nil, true
	}
	if this.Left != nil && other.Left == nil {
		return nil, false
	}
	if (this.Right != nil && other.Right == nil) || (this.Right == nil && other.Right != nil) {
		return nil, false
	}
	if this.Left == nil && other.Left != nil {
		return nil, true
	}
	if this.Left == nil && this.Right == nil && this.Rp != -1 && this.Lp != -1 {
		LpMsg := (*newData)[other.Lp]
		if this.Lp != other.Lp {
			return &LpMsg, false
		}
		RpMsg := (*newData)[other.Rp]
		if this.Rp != other.Rp {
			return &RpMsg, false
		}
		oldLpMsg := (*oldData)[other.Lp]
		if LpMsg != oldLpMsg {
			return &LpMsg, false
		}
		oldRpMsg := (*oldData)[other.Rp]
		if RpMsg != oldRpMsg {
			return &RpMsg, false
		}
	}
	valid, b := this.Left.Valid(other.Left, oldData, newData)
	if !b {
		return valid, b
	}
	node, b2 := this.Right.Valid(other.Right, oldData, newData)
	if !b2 {
		return node, b2
	}
	return nil, true
}

На самом деле это двоичное разделение. Нам нужно только рекурсивно найти последний узел ошибки. Однако с этим кодом есть проблема, обнаружил ли кто-нибудь это?

Например, есть такой узел

Дерево Меркельнода проверка
Дерево Меркельнода проверка

С B проблем нет, с C проблем нет, но что делать, если во время передачи клиента в A возникает ошибка?

Итак, здесь нам также необходимо проверить текущий узел

Окончательный код выглядит следующим образом

Язык кода:go
копировать
if b && b2 && !this.Equals(other) {
   return nil, false
}

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

Если вам нужно вернуться, сделайте абстракцию интерфейса самостоятельно, хаха, окончательный код

Язык кода:go
копировать
func (this *MerkalNode) Valid(other *MerkalNode, oldData *[]Message, newData *[]Message) (*Message, bool) {
   if this.Equals(other) {
      return nil, true
   }
   if this.Left != nil && other.Left == nil {
      return nil, false
   }
   if (this.Right != nil && other.Right == nil) || (this.Right == nil && other.Right != nil) {
      return nil, false
   }
   if this.Left == nil && other.Left != nil {
      return nil, true
   }
   if this.Left == nil && this.Right == nil && this.Rp != -1 && this.Lp != -1 {
      LpMsg := (*newData)[other.Lp]
      if this.Lp != other.Lp {
         return &LpMsg, false
      }
      RpMsg := (*newData)[other.Rp]
      if this.Rp != other.Rp {
         return &RpMsg, false
      }
      oldLpMsg := (*oldData)[other.Lp]
      if LpMsg != oldLpMsg {
         return &LpMsg, false
      }
      oldRpMsg := (*oldData)[other.Rp]
      if RpMsg != oldRpMsg {
         return &RpMsg, false
      }
   }
   valid, b := this.Left.Valid(other.Left, oldData, newData)
   if !b {
      return valid, b
   }
   node, b2 := this.Right.Valid(other.Right, oldData, newData)
   if !b2 {
      return node, b2
   }
   if b && b2 && !this.Equals(other) {
      return nil, false
   }
   return nil, true
}

некоторые базовыеизCRUDи Дерево Меркельизгенерировать

Это легко, я напишу их все вместе. Конкретный исходный код вы можете посмотреть в моем репозитории на GitHub, хе-хе.

BlockChain

Язык кода:go
копировать
func (this *BlockChain) String() string {
	marshal, _ := json.Marshal(this)
	return string(marshal)
}
func NewBlockChain(treeSize int64) *BlockChain {
	return &BlockChain{TreeSize: treeSize, Version: "V1.0.0"}
}

func hash(node BlockNode) string {
	sum256 := sha256.Sum256([]byte(node.String()))
	return fmt.Sprintf("0x%x", sum256)
}
func (this *BlockChain) AddMsg(message *merkal.Message) {
	nodeLen := 0
	Lock.Lock()
	nodeLen = len(this.Nodes)
	defer Lock.Unlock()
	if nodeLen == 0 {
		this.AddNode(NewBlockNode("head", this.Version, merkal.MerkalTree{}))
		nodeLen = len(this.Nodes)
	}
	prev := this.Nodes[nodeLen-1]
	useSize := prev.RootTree.Size()
	if useSize < this.TreeSize {
		prev.RootTree.AddNode(message)
		return
	}
	tree := new(merkal.MerkalTree)
	tree.AddNode(message)
	node := NewBlockNode(hash(*prev), this.Version, *tree)
	this.AddNode(node)

}
func (this *BlockChain) AddNode(node *BlockNode) {
	defer func() {
		a := recover()
		if a != nil {
			fmt.Println(a)
		}
	}()
	if node.Version != this.Version {
		panic("номер версиинеправильный")
	}
	nodeLen := len(this.Nodes)
	if nodeLen == 0 {
		this.Nodes = append(this.Nodes, NewBlockNode("head", this.Version, merkal.MerkalTree{}))
		nodeLen = len(this.Nodes)
	}
	prev := this.Nodes[nodeLen-1]
	node.PrevHash = hash(*prev)
	this.Nodes = append(this.Nodes, node)
}

BlockNode

Язык кода:go
копировать
func NewBlockNode(prevHash string, version string, rootTree merkal.MerkalTree) *BlockNode {
   node := &BlockNode{PrevHash: prevHash,
      Version:   version,
      Datestamp: long(time.Now().UnixMilli()),
      RootTree:  rootTree,
      Nonce:     getNonce(),
   }
   node.Build()
   return node
}

func getNonce() string {
   return string("test")
}

func (this *BlockNode) Build() {
   this.RootTreeCode = this.RootTree.RootHash
   this.LocalTreeSize = this.RootTree.Size()
}

func (this *BlockNode) Valid(node *BlockNode) bool {
   defer func() bool {
      err := recover()
      if err != nil {
         log.Println(err)
         return false
      }
      return true
   }()
   this.Build()
   node.Build()
   localVersion, localSize := node.Version, node.LocalTreeSize
   if this.Version != localVersion || this.LocalTreeSize != localSize {
      return false
   }
   valid, b := this.RootTree.Valid(node.RootTree)
   if b {
      return true
   } else {
      panic(valid.String())
   }
}
func (this *BlockNode) String() string {
   this.LocalTreeSize = this.RootTree.Size()
   jsonBytes, _ := json.Marshal(this)
   return string(jsonBytes)
}

MerkalNode

Язык кода:go
копировать
func (this *MerkalNode) String() string {
   marshal, _ := json.Marshal(this)
   return string(marshal)
}

func (this *MerkalNode) Equals(other *MerkalNode) bool {
   if other == nil {
      return false
   }
   return reflect.DeepEqual(this, other)
}
func NewMerkalNode(Left *MerkalNode, Right *MerkalNode, Hash string, Lp int, Rp int) *MerkalNode {
   res := &MerkalNode{Left: Left, Right: Right, Hash: Hash, Lp: Lp, Rp: Rp}
   //fmt.Println(res)
   return res
}

MerkalTree

Язык кода:go
копировать
func getSize(node *MerkalNode, size int64) int64 {
   if node == nil {
      return size
   }
   size = getSize(node.Left, size)
   size++
   size = getSize(node.Right, size)
   return size
}
func (this MerkalTree) Size() int64 {
   return getSize(this.RootNode, 0)
}
func (this *MerkalTree) AddNode(data *Message) {
   if this.DataSet == nil {
      this.DataSet = (new([]Message))
   }
   messages := append((*this.DataSet), *data)
   this.DataSet = (&messages)
   this.Detail()
}

func (this *MerkalTree) String() string {
   res, _ := json.Marshal(this)
   return string(res)
}

func (this *MerkalTree) binaryDetail(data *[]Message, l int, r int) (resNode *MerkalNode) {
   if r == l {
      resNode = NewMerkalNode(nil, nil, hash(&(*data)[l], nil), l, r)
      return resNode
   }
   if r-l == 1 {
      resNode = NewMerkalNode(nil, nil, hash(&(*data)[l], &(*data)[r]), l, r)
      return resNode
   }
   mid := (l-r)>>1 + r
   left := this.binaryDetail(data, l, mid)
   right := this.binaryDetail(data, mid+1, r)
   resNode = NewMerkalNode(left, right, hash(left, right), -1, -1)
   return resNode
}

func (this *MerkalTree) Detail() {
   data := this.DataSet
   l := 0
   r := len(*data) - 1
   detail := this.binaryDetail(data, l, r)
   this.RootNode = detail
   this.RootHash = (hash(detail, nil))
}

func NewMerkalTree(dataSet *[]Message) (res *MerkalTree) {
	res = &MerkalTree{DataSet: dataSet}
	res.RootHash = hash(res, nil)
	return res
}

Message

Язык кода:go
копировать
func (this *Message) String() string {
   res, _ := json.Marshal(this)
   return string(res)
}

func (this *Message) Equals(other Message) bool {
   return reflect.DeepEqual(this, other)
}

общедоступный родительский интерфейс

Язык кода:go
копировать
type Object interface {
   String() string
}

Подвести итог

Вышеупомянутое содержание — это то, чем я поделюсь в этом выпуске. Я опубликую информацию о Raft и bftp после того, как попрактикуюсь в них в будущем. Вы также можете проверить etcd, чтобы расширить свои знания.

исходный кодgithubадрес:https://github.com/Karosown/blockLink.git

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

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода