چگونه بلوک ها و تراکنش ها را در بلاک چین Go خود طراحی کردم

برای اینکه در نهایت به یک بلاک چین و نه فقط یک پایگاه داده ختم شود، باید 3 عنصر مهم را به پروژه خود اضافه کنیم:

  • شرح ساختار داده بلوک و روش ها
  • شرح ساختار داده ها و روش های تراکنش
  • توابع بلاک چین که بلوک ها را در یک پایگاه داده ذخیره می کند و آنها را بر اساس هش یا ارتفاع (یا چیز دیگری) در آنجا پیدا می کند.

چگونه بلوک ها و تراکنش ها را در بلاک چین Go خود طراحی کردم

این دومین مقاله در مورد بلاک چین برای صنعت است، اولین مقاله اینجا.

با یادآوری سوالاتی که خوانندگان در مورد مقاله قبلی این مجموعه از من پرسیدند، لازم به ذکر است: در این مورد، پایگاه داده LevelDB برای ذخیره داده های بلاک چین استفاده می شود، اما هیچ چیز مانع از استفاده شما از هیچ، مثلاً MySQL نمی شود. حال بیایید به ساختار این داده ها نگاه کنیم.

بیایید با معاملات شروع کنیم: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

در اینجا ساختار داده آن است:

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 نوع داده (برای تراکنش 2)، هش آن تراکنش، نوع خود تراکنش، مهر زمانی و ورودی ها و خروجی ها را ذخیره می کند. ورودی های TxIn هش تراکنشی که خروجی آن ارجاع داده شده است، تعداد این خروجی و بایت کد را ذخیره می کند و خروجی های TxOut مقداری مقدار و همچنین بایت کد را ذخیره می کند.

حالا بیایید ببینیم که یک تراکنش چه اقداماتی می تواند روی داده های خود انجام دهد، یعنی. بیایید به روش ها نگاه کنیم.

برای ایجاد یک تراکنش، از تابعtransaction.NewTransaction(txtype byte) *TX استفاده کنید.

روش AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) یک ورودی به تراکنش اضافه می کند.

روش AddTxOut(value int, data []byte) (*TxOut, error) یک خروجی به تراکنش اضافه می کند.

متد ToBytes() []byte تراکنش را به یک تکه بایت تبدیل می کند.

رشته تابع داخلی preByteHash(bytes []byte) در Build() و Check() استفاده می شود تا هش تراکنش تولید شده با هش تراکنش های تولید شده از برنامه های جاوا اسکریپت سازگار باشد.

متد Build() هش تراکنش را به صورت زیر تنظیم می کند: tx.TxHash = preByteHash(tx.ToBytes()).

متد رشته ToJSON() یک تراکنش را به یک رشته JSON تبدیل می کند.

روش خطای FromJSON(data []byte) یک تراکنش را از فرمت JSON که به عنوان یک تکه بایت ارسال شده بارگیری می کند.

متد Check()bool هش حاصل از فیلد هش تراکنش را با هش به دست آمده در نتیجه هش کردن این تراکنش (با نادیده گرفتن فیلد هش) مقایسه می کند.

تراکنش ها به بلوک اضافه می شوند: github.com/Rusldv/bcstartup/blob/master/block/builder.go

ساختار داده بلوک حجیم تر است:

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 نوع داده را ذخیره می کند، گره از آن استفاده می کند و بلوک را از یک تراکنش یا داده های دیگر متمایز می کند. برای یک بلوک این مقدار 1 است.

BlockHeight ارتفاع بلوک را ذخیره می کند.
مهر زمانی.
HeaderSize اندازه بلوک بر حسب بایت است.
PrevBlockHash هش بلوک قبلی است و SelfBlockHash هش بلوک فعلی است.
TxsHash یک هش کلی از تراکنش ها است.
مرکل روت ریشه درخت مرکل است.

علاوه بر این در فیلدها کلید عمومی سازنده بلوک، امضای سازنده، نسخه بلوک، تعداد تراکنش‌های بلوک و خود این تراکنش‌ها وجود دارد.

بیایید به روش های آن نگاه کنیم:
برای ایجاد یک بلوک، از تابع ()block استفاده کنید. نوع بلوک نیز از ثابت بسته انواع تنظیم می شود:

b.DataType = types.BLOCK_TYPE.

روش AddTx(tx *transaction.TX) یک تراکنش را به یک بلوک اضافه می کند.

متد Build() مقادیر را در فیلدهای بلوک بارگذاری می کند و هش فعلی آن را تولید و تنظیم می کند.

متد ToBytesHeader() []byte هدر بلوک (بدون تراکنش) را به یک تکه بایت تبدیل می کند.

متد رشته ToJSON () بلوک را به فرمت JSON در یک نمایش رشته ای از داده ها تبدیل می کند.

روش خطای FromJSON(data []byte) داده ها را از JSON در یک ساختار بلوکی بارگیری می کند.

متد Check() bool یک هش بلوک تولید می کند و آن را با آنچه در فیلد هش بلوک مشخص شده مقایسه می کند.

متد رشته ()GetTxsHash کل هش تمام تراکنش‌های بلوک را برمی‌گرداند.

متد GetMerkleRoot() ریشه درخت Merkle را برای تراکنش های یک بلوک مشخص می کند.

روش Sign (رشته privk) یک بلوک را با کلید خصوصی سازنده بلوک امضا می کند.

متد SetHeight(height int) ارتفاع بلوک را در قسمت ساختار بلوک می نویسد.

متد GetHeight() int ارتفاع بلوک را همانطور که در فیلد مربوطه ساختار بلوک مشخص شده است برمی گرداند.

متد ToGOBBytes() []byte یک بلوک را در قالب GOB رمزگذاری می کند و آن را به عنوان یک تکه بایت برمی گرداند.

روش خطای FromGOBBytes(data []byte) داده های بلوک را از برش بایت ارسال شده در قالب GOB به ساختار بلوک می نویسد.

متد رشته ()GetHash هش بلوک داده شده را برمی گرداند.

متد رشته ()GetPrevHash هش بلوک قبلی را برمی گرداند.

متد SetPublicKey (رشته pubk) کلید عمومی سازنده بلوک را در بلوک می نویسد.

بنابراین، با استفاده از متدهای شی Block، به راحتی می‌توانیم آن را به قالبی برای انتقال از طریق شبکه و ذخیره در پایگاه داده LevelDB تبدیل کنیم.

توابع بسته بلاک چین مسئول ذخیره در بلاک چین هستند: github.com/Rusldv/bcstartup/tree/master/blockchain

برای انجام این کار، بلوک باید رابط IBlock را پیاده سازی کند:

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

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

}

هنگامی که بسته در تابع init() مقدار دهی اولیه می شود، اتصال پایگاه داده یک بار ایجاد می شود:

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

CloseDB() یک wrapper برای db.Cloce() است - پس از کار با توابع بسته برای بستن اتصال به پایگاه داده فراخوانی می شود.

تابع خطای SetTargetBlockHash (رشته هش) هش بلوک فعلی را با کلید مشخص شده توسط ثابت BLOCK_HASH در پایگاه داده می نویسد.

تابع GetTargetBlockHash () (رشته، خطا) هش بلوک فعلی ذخیره شده در پایگاه داده را برمی گرداند.

تابع خطای SetTargetBlockHeight (height int) مقدار ارتفاع بلاک چین برای گره را با کلید مشخص شده توسط ثابت BLOCK_HEIGHT به پایگاه داده می نویسد.

تابع GetTargetBlockHeight () (int, error) ارتفاع بلاک چین را برای یک گره معین ذخیره شده در پایگاه داده برمی گرداند.

تابع Bool CheckBlock (block IBlock) قبل از افزودن این بلوک به بلاک چین، صحت یک بلوک را بررسی می کند.

تابع خطای AddBlock(block IBlock) یک بلوک به زنجیره بلوکی اضافه می کند.

توابع بازیابی و مشاهده بلوک ها در فایل explore.go بسته بلاک چین هستند:

تابع GetBlockByHash (رشته هش) (*block.Block، error) یک شیء بلوک خالی ایجاد می کند، یک بلوک را از پایگاه داده در آن بارگذاری می کند که هش آن به آن ارسال شده است، و یک اشاره گر به آن برمی گرداند.

ایجاد یک بلوک پیدایش توسط تابع خطای Genesis() از فایل genesis.go بسته بلاک چین انجام می شود.

مقاله بعدی در مورد اتصال کلاینت ها به یک گره با استفاده از مکانیسم WebSocket صحبت خواهد کرد.

منبع: www.habr.com

اضافه کردن نظر