© 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("Alex відправив $30 Барбарі")
	bc.Print("Оригінальний Блокчейн")

	// Підробка
	bc.Blocks[1].Data = []byte("Steve відправив Alex $1000")
	bc.Print("Підроблений Блокчейн")
}

Блокчейн має потенціал змінити багато галузей, надаючи безпечний і прозорий спосіб запису транзакцій.

У цьому блозі ми дослідили базову реалізацію блокчейну на Go, дізналися, як створюються блоки, обчислюються хеші і перевіряється цілісність ланцюжка. Є ще багато чого, що можна вивчити, наприклад, алгоритми консенсусу і розумні контракти.

Я сподіваюся, що цей пост дав вам гарне розуміння того, як працює блокчейн і як його можна реалізувати.