© 2024 Нуран Аскеров.

Изучение блокчейна на языке Go

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

Блок

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

type Block struct {
	Timestamp int64
	Data      []byte
	PrevHash  []byte
	Hash      []byte
}

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

Чтобы создать новый блок, давайте определим эту вспомогательную функцию.

func NewBlock(data []byte, prevHash []byte) *Block {
	block := &Block{
		Timestamp: time.Now().Unix(),
		Data:      data,
		PrevHash:  prevHash,
		Hash:      []byte{},
	}
	return block
}

Одной из основных компонентов блокчейна является используемый алгоритм хэширования для вычисления хэша каждого блока. В нашей реализации мы используем алгоритм SHA-256 для вычисления хэша на основе временной метки, данных и хэша предыдущего блока. Давайте определим его:

func (b *Block) CalculateHash() []byte {
	timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))
	headers := bytes.Join([][]byte{b.PrevHash, b.Data, timestamp}, []byte{})
	hash := sha256.Sum256(headers)
	return hash[:]
}

Давайте также определим этот удобный метод для печати блока.

func (b *Block) Print() {
	fmt.Printf("Пред. хеш : %x\n", b.PrevHash)
	fmt.Printf("Данные    : %s\n", b.Data)
	fmt.Printf("Хеш       : %x\n", b.Hash)
}

Блокчейн

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

type Blockchain struct {
	Blocks []*Block
}

Чтобы создать новый блокчейн, мы используем функцию NewBlockchain:

func NewBlockchain() *Blockchain {
	var genesisBlock = NewBlock([]byte("Genesis Block"), []byte{})
	genesisBlock.Hash = genesisBlock.CalculateHash()
	return &Blockchain{[]*Block{genesisBlock}}
}

Эта функция создает новый блокчейн с блоком-генезисом, который является первым блоком в цепочке.

Чтобы добавить новый блок в блокчейн, у нас есть метод AddBlock:

func (bc *Blockchain) AddBlock(data string) {
	prevBlock := bc.Blocks[len(bc.Blocks)-1]
	newBlock := NewBlock([]byte(data), prevBlock.Hash)
	newBlock.Hash = newBlock.CalculateHash()
	bc.Blocks = append(bc.Blocks, newBlock)
}

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

Одним из важных аспектов блокчейна является его способность обнаруживать подделки. Мы можем проверить, действителен ли блокчейн, используя метод IsValid:

func (bc *Blockchain) IsValid() bool {
	for i := 1; i < len(bc.Blocks); i++ {
		block := bc.Blocks[i]
		prevBlock := bc.Blocks[i-1]

		if !bytes.Equal(block.Hash, block.CalculateHash()) {
			return false
		}

		if !bytes.Equal(block.PrevHash, prevBlock.Hash) {
			return false
		}
	}
	return true
}

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

Нам также нужно определить метод для печати всего блокчейна:

func (bc *Blockchain) Print(label string) {
	print("\n==============================================\n\n")
	fmt.Printf("Label: %s\n", label)
	fmt.Printf("Valid: %t\n", bc.IsValid())
	println()

	for _, block := range bc.Blocks {
		block.Print()
		println()
	}
}

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

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

func main() {
	bc := NewBlockchain()

	// Оригинал
	bc.AddBlock("Steve отправил $250 Бобу")
	bc.AddBlock("Алекс отправил $30 Барбаре")
	bc.Print("Исходный Блокчейн") 


	// Модификация
	bc.Blocks[1].Data = []byte("Steve отправил $1000 Алексу")
	bc.Print("Поддельный Блокчейн") 
}

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

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

Я надеюсь, что этот пост дал вам хорошее понимание того, как работает блокчейн и как его можно реализовать.