Qanday qilib men Go blokcheynimda bloklar va tranzaktsiyalarni yaratdim

Oxir oqibatda faqat ma'lumotlar bazasi emas, balki blokcheyn bilan yakunlash uchun loyihamizga 3 ta muhim elementni qo'shishimiz kerak:

  • Blok ma'lumotlar strukturasi va usullari tavsifi
  • Ma'lumotlar tuzilishi va tranzaksiya usullarining tavsifi
  • Bloklarni ma'lumotlar bazasida saqlaydigan va ularni xesh yoki balandlik (yoki boshqa narsa) bo'yicha topadigan blokcheyn funktsiyalari.

Qanday qilib men Go blokcheynimda bloklar va tranzaktsiyalarni yaratdim

Bu sanoat uchun blokcheyn haqida ikkinchi maqola, birinchi shu yerda.

O'quvchilarning ushbu seriyadagi oldingi maqola haqida menga bergan savollarini eslab, shuni ta'kidlash kerak: bu holda, LevelDB ma'lumotlar bazasi blokcheyn ma'lumotlarini saqlash uchun ishlatiladi, ammo hech narsa boshqa, aytaylik, MySQL dan foydalanishga to'sqinlik qilmaydi. Endi ushbu ma'lumotlarning tuzilishini ko'rib chiqamiz.

Tranzaktsiyalardan boshlaylik: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Mana uning ma'lumotlar tuzilishi:

type TX struct {
	DataType byte		
	TxHash string 
	TxType byte	
	Timestamp int64		
	INs []TxIn
	OUTs []TxOut
}

type TxIn struct {
	ThatTxHash string
	TxOutN int
	ByteCode string
}

type TxOut struct {
	Value int
	ByteCode string
}

TX ma'lumotlar turini (2-tranzaksiya uchun), ushbu tranzaksiyaning xeshini, tranzaktsiyaning o'zi turini, vaqt tamg'asini, kirish va chiqishlarni saqlaydi. TxIn kirishlari chiqishiga havola qilingan tranzaksiya xeshini, ushbu chiqish va bayt kodining sonini, TxOut chiqishi esa ba'zi qiymatlarni va bayt kodini saqlaydi.

Keling, tranzaksiya o'z ma'lumotlarida qanday harakatlarni amalga oshirishi mumkinligini ko'rib chiqaylik, ya'ni. Keling, usullarni ko'rib chiqaylik.

Tranzaksiya yaratish uchun tranzaksiyadan foydalaning.NewTransaction(txtype bayt) *TX funksiyasidan foydalaning.

AddTxIn(thattxhash []bayt, txoutn int, kod []bayt) (*TxIn, xato) usuli tranzaktsiyaga kirish kiritadi.

AddTxOut(value int, data []bayt) (*TxOut, error) usuli tranzaktsiyaga chiqish qo'shadi.

ToBytes() []bayt usuli tranzaksiyani bayt tilimga aylantiradi.

PreByteHash(bayt []bayt) ichki funksiyasi Build() va Check() da yaratilgan tranzaksiya xeshini JavaScript ilovalarida yaratilgan tranzaksiya xeshlari bilan mos qilish uchun ishlatiladi.

Build() usuli tranzaksiya xeshini quyidagicha o'rnatadi: tx.TxHash = preByteHash(tx.ToBytes()).

ToJSON() string usuli tranzaksiyani JSON qatoriga aylantiradi.

FromJSON(ma'lumotlar []bayt) xato usuli bayt tilim sifatida uzatilgan JSON formatidan tranzaksiyani yuklaydi.

Check() bool usuli tranzaksiya xesh maydonidan olingan xeshni ushbu tranzaksiyani xeshlash natijasida olingan xeshni (xesh maydoniga e'tibor bermasdan) solishtiradi.

Bitimlar blokga qo'shiladi: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Blok ma'lumotlar strukturasi yanada hajmli:

type Block struct {
	DataType byte				
	BlockHeight int					
        Timestamp int64				 
        HeaderSize int					
        PrevBlockHash string				 
        SelfBlockHash string			
	TxsHash string			
	MerkleRoot string
	CreatorPublicKey string			
	CreatorSig string
	Version int
	TxsN int
	Txs []transaction.TX
}

DataType ma'lumotlar turini saqlaydi, tugun undan foydalanadi va blokni tranzaksiya yoki boshqa ma'lumotlardan ajratib turadi. Blok uchun bu qiymat 1 ga teng.

BlockHeight blokning balandligini saqlaydi.
Vaqt tamg'asi vaqt tamg'asi.
HeaderSize - baytdagi blok hajmi.
PrevBlockHash oldingi blokning xeshi, SelfBlockHash esa joriy blokning xeshidir.
TxsHash - tranzaktsiyalarning umumiy xeshi.
MerkleRoot Merkle daraxtining ildizidir.

Keyinchalik maydonlarda blok yaratuvchisining ochiq kaliti, yaratuvchining imzosi, blok versiyasi, blokdagi tranzaktsiyalar soni va ushbu tranzaktsiyalarning o'zi mavjud.

Keling, uning usullarini ko'rib chiqaylik:
Blok yaratish uchun block.NewBlock() funksiyasidan foydalaning: NewBlock(prevBlockHash string, height int) *Blok, oldingi blokning xeshini va blokcheyndagi yaratilgan blok uchun belgilangan balandlikni oladi. Blok turi ham turlar to'plami konstantasidan o'rnatiladi:

b.DataType = types.BLOCK_TYPE.

AddTx(tx *transaction.TX) usuli tranzaktsiyani blokga qo'shadi.

Build() usuli qiymatlarni blok maydonlariga yuklaydi va joriy xeshni yaratadi va o'rnatadi.

ToBytesHeader() []bayt usuli blok sarlavhasini (tranzaksiyalarsiz) bayt tilimga aylantiradi.

ToJSON() string usuli blokni JSON formatiga ma'lumotlarning satr ko'rinishida o'zgartiradi.

FromJSON(ma'lumotlar []bayt) xato usuli JSON'dan ma'lumotlarni blok tuzilishiga yuklaydi.

Check() bool usuli blok xesh hosil qiladi va uni blok xesh maydonida ko'rsatilgan bilan solishtiradi.

GetTxsHash() string usuli blokdagi barcha tranzaksiyalarning umumiy xeshini qaytaradi.

GetMerkleRoot() usuli blokdagi tranzaktsiyalar uchun Merkle daraxtining ildizini belgilaydi.

Sign(privk string) usuli blok yaratuvchining shaxsiy kaliti bilan blokni imzolaydi.

SetHeight(height int) usuli blokning balandligini blok strukturasi maydoniga yozadi.

GetHeight() int usuli blok strukturasining tegishli maydonida belgilangan blok balandligini qaytaradi.

ToGOBBytes() []bayt usuli blokni GOB formatida kodlaydi va uni bayt tilim sifatida qaytaradi.

FromGOBBytes(ma'lumotlar []bayt) xato usuli blok ma'lumotlarini blok tuzilishiga o'tkazilgan bayt tilimdan GOB formatida yozadi.

GetHash() string usuli berilgan blokning xeshini qaytaradi.

GetPrevHash() string usuli oldingi blokning xeshini qaytaradi.

SetPublicKey(pubk string) usuli blok yaratuvchining ochiq kalitini blokga yozadi.

Shunday qilib, Block ob'ektining usullaridan foydalanib, biz uni tarmoq orqali uzatish va LevelDB ma'lumotlar bazasiga saqlash uchun formatga osongina o'zgartirishimiz mumkin.

Blokcheyn paketining funktsiyalari blokcheynga saqlash uchun javobgardir: github.com/Rusldv/bcstartup/tree/master/blockchain

Buning uchun blok IBlock interfeysini amalga oshirishi kerak:

type IGOBBytes interface {
	ToGOBBytes() []byte
	FromGOBBytes(data []byte) error
}

type IBlock interface {
	IGOBBytes
	GetHash() string
	GetPrevHash() string
	GetHeight() int
	Check() bool

}

Ma'lumotlar bazasi ulanishi paket init() funksiyasida ishga tushirilganda bir marta yaratiladi:

db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB() db.Cloce() uchun oΚ»ram boΚ»lib, maΚΌlumotlar bazasiga ulanishni yopish uchun paket funksiyalari bilan ishlagandan keyin chaqiriladi.

SetTargetBlockHash(xesh string) xato funksiyasi joriy blokning xeshini ma'lumotlar bazasiga BLOCK_HASH doimiysi tomonidan belgilangan kalit bilan yozadi.

GetTargetBlockHash() (string, xato) funksiyasi ma'lumotlar bazasida saqlangan joriy blokning xeshini qaytaradi.

SetTargetBlockHeight(height int) xato funksiyasi maΚΌlumotlar bazasiga BLOCK_HEIGHT doimiysi bilan belgilangan kalit bilan tugun uchun blokcheyn balandligi qiymatini yozadi.

GetTargetBlockHeight() (int, xato) funktsiyasi ma'lumotlar bazasida saqlangan berilgan tugun uchun blokcheyn balandligini qaytaradi.

CheckBlock(block IBlock) bool funksiyasi ushbu blokni blokcheynga qo'shishdan oldin blokning to'g'riligini tekshiradi.

AddBlock(block IBlock) xato funksiyasi blokcheynga blok qoβ€˜shadi.

Bloklarni olish va ko'rish funktsiyalari blockchain paketining explore.go faylida joylashgan:

GetBlockByHash(xesh string) (*block.Block, error) funksiyasi bo'sh blok ob'ektini yaratadi, unga ma'lumotlar bazasidan blokni yuklaydi, uning xeshi unga uzatiladi va unga ko'rsatgichni qaytaradi.

Genesis blokini yaratish blokcheyn paketining genesis.go faylidan Genesis() xato funksiyasi orqali amalga oshiriladi.

Keyingi maqolada WebSocket mexanizmi yordamida mijozlarni tugunga ulash haqida gap boradi.

Manba: www.habr.com

a Izoh qo'shish