Cách tôi thiết kế các khối và giao dịch trong chuỗi khối Go của mình

Để cuối cùng đạt được một blockchain chứ không chỉ là cơ sở dữ liệu, chúng tôi cần thêm 3 yếu tố quan trọng vào dự án của mình:

  • Mô tả cấu trúc và phương thức dữ liệu khối
  • Mô tả cấu trúc dữ liệu và phương thức giao dịch
  • Các hàm chuỗi khối lưu các khối trong cơ sở dữ liệu và tìm chúng ở đó theo hàm băm hoặc chiều cao của chúng (hoặc thứ gì khác).

Cách tôi thiết kế các khối và giao dịch trong chuỗi khối Go của mình

Đây là bài viết thứ hai về blockchain cho ngành công nghiệp, bài viết đầu tiên đây.

Ghi nhớ những câu hỏi mà độc giả đã hỏi tôi về bài viết trước trong loạt bài này, cần lưu ý: trong trường hợp này, cơ sở dữ liệu LevelDB được sử dụng để lưu trữ dữ liệu blockchain, nhưng không có gì ngăn cản bạn sử dụng bất kỳ cơ sở dữ liệu nào khác, chẳng hạn như MySQL. Bây giờ hãy xem cấu trúc của dữ liệu này.

Hãy bắt đầu với các giao dịch: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Đây là cấu trúc dữ liệu của nó:

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 lưu trữ loại dữ liệu (đối với giao dịch 2), hàm băm của giao dịch đó, loại giao dịch, dấu thời gian cũng như đầu vào và đầu ra. Đầu vào TxIn lưu trữ hàm băm của giao dịch có đầu ra được tham chiếu, số đầu ra và mã byte này, còn đầu ra TxOut lưu trữ một số giá trị và cả mã byte.

Bây giờ hãy xem giao dịch có thể thực hiện những hành động nào trên dữ liệu của nó, tức là. Chúng ta hãy xem xét các phương pháp.

Để tạo một giao dịch, hãy sử dụng hàm giao dịch.NewTransaction(txtype byte) *TX.

Phương thức AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) thêm đầu vào vào giao dịch.

Phương thức AddTxOut(value int, data []byte) (*TxOut, error) thêm đầu ra vào giao dịch.

Phương thức ToBytes() []byte biến giao dịch thành một lát byte.

Chuỗi hàm nội bộ preByteHash(bytes []byte) được sử dụng trong Build() và Check() để làm cho hàm băm giao dịch được tạo ra tương thích với hàm băm giao dịch được tạo từ các ứng dụng JavaScript.

Phương thức Build() đặt hàm băm giao dịch như sau: tx.TxHash = preByteHash(tx.ToBytes()).

Phương thức chuỗi ToJSON() chuyển đổi một giao dịch thành chuỗi JSON.

Phương thức lỗi FromJSON(data []byte) tải một giao dịch từ định dạng JSON được truyền dưới dạng một lát byte.

Phương thức Check() bool so sánh giá trị băm thu được từ trường băm giao dịch với giá trị băm thu được từ quá trình băm giao dịch này (bỏ qua trường băm).

Giao dịch được thêm vào khối: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Cấu trúc dữ liệu khối đồ sộ hơn:

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 lưu trữ kiểu dữ liệu, nút sử dụng nó và phân biệt khối với giao dịch hoặc dữ liệu khác. Đối với một khối, giá trị này là 1.

BlockHeight lưu trữ chiều cao của khối.
Dấu thời gian dấu thời gian.
HeaderSize là kích thước khối tính bằng byte.
PrevBlockHash là hàm băm của khối trước đó và SelfBlockHash là hàm băm của khối hiện tại.
TxsHash là một hàm băm chung của các giao dịch.
MerkleRoot là gốc của cây Merkle.

Hơn nữa, trong các trường còn có khóa chung của người tạo khối, chữ ký của người tạo, phiên bản của khối, số lượng giao dịch trong khối và chính các giao dịch này.

Hãy xem xét các phương pháp của nó:
Để tạo một khối, hãy sử dụng hàm block.NewBlock(): NewBlock(prevBlockHash string, Height int) *Block, lấy hàm băm của khối trước đó và chiều cao được đặt cho khối được tạo trong chuỗi khối. Loại khối cũng được đặt từ hằng số gói loại:

b.DataType = types.BLOCK_TYPE.

Phương thức AddTx(tx *transaction.TX) thêm giao dịch vào một khối.

Phương thức Build() tải các giá trị vào các trường của khối, đồng thời tạo và đặt hàm băm hiện tại của nó.

Phương thức ToBytesHeader() []byte chuyển đổi tiêu đề khối (không có giao dịch) thành một lát byte.

Phương thức chuỗi ToJSON() chuyển đổi khối sang định dạng JSON dưới dạng chuỗi biểu diễn dữ liệu.

Phương thức lỗi FromJSON(data []byte) tải dữ liệu từ JSON vào cấu trúc khối.

Phương thức bool Check() tạo ra một khối băm và so sánh nó với khối được chỉ định trong trường khối băm.

Phương thức chuỗi GetTxsHash() trả về tổng số băm của tất cả các giao dịch trong khối.

Phương thức GetMerkleRoot() chỉ định gốc của cây Merkle cho các giao dịch trong một khối.

Phương thức Sign(privk string) ký một khối bằng khóa riêng của người tạo khối.

Phương thức SetHeight(height int) ghi chiều cao của khối vào trường cấu trúc khối.

Phương thức int GetHeight() trả về chiều cao của khối như được chỉ định trong trường tương ứng của cấu trúc khối.

Phương thức ToGOBBytes() []byte mã hóa một khối ở định dạng GOB và trả về nó dưới dạng một lát byte.

Phương thức lỗi FromGOBBytes(data []byte) ghi dữ liệu khối vào cấu trúc khối từ lát byte được truyền ở định dạng GOB.

Phương thức chuỗi GetHash() trả về giá trị băm của khối đã cho.

Phương thức chuỗi GetPrevHash() trả về giá trị băm của khối trước đó.

Phương thức SetPublicKey(pubk string) ghi khóa chung của người tạo khối vào khối.

Do đó, bằng cách sử dụng các phương thức của đối tượng Block, chúng ta có thể dễ dàng chuyển đổi nó sang định dạng để truyền qua mạng và lưu vào cơ sở dữ liệu LevelDB.

Các chức năng của gói blockchain chịu trách nhiệm lưu vào blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

Để làm được điều này, khối phải triển khai giao diện IBlock:

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

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

}

Kết nối cơ sở dữ liệu được tạo một lần khi gói được khởi tạo trong hàm init():

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

CloseDB() là một trình bao bọc cho db.Cloce() - được gọi sau khi làm việc với các hàm gói để đóng kết nối tới cơ sở dữ liệu.

Hàm lỗi SetTargetBlockHash(chuỗi băm) ghi hàm băm của khối hiện tại bằng khóa được chỉ định bởi hằng số BLOCK_HASH vào cơ sở dữ liệu.

Hàm GetTargetBlockHash() (chuỗi, lỗi) trả về hàm băm của khối hiện tại được lưu trữ trong cơ sở dữ liệu.

Hàm lỗi SetTargetBlockHeight(height int) ghi vào cơ sở dữ liệu giá trị chiều cao blockchain của nút có khóa được chỉ định bởi hằng số BLOCK_HEIGHT.

Hàm GetTargetBlockHeight() (int, error) trả về chiều cao của blockchain cho một nút nhất định, được lưu trữ trong cơ sở dữ liệu.

Hàm bool CheckBlock(block IBlock) kiểm tra tính chính xác của một khối trước khi thêm khối này vào chuỗi khối.

Hàm lỗi AddBlock(block IBlock) thêm một khối vào blockchain.

Các chức năng truy xuất và xem các khối có trong tệp explorer.go của gói blockchain:

Hàm GetBlockByHash(hash string) (*block.Block, error) tạo một đối tượng khối trống, tải một khối vào nó từ cơ sở dữ liệu, hàm băm của khối đó được truyền cho nó và trả về một con trỏ tới nó.

Việc tạo khối Genesis được thực hiện bởi hàm lỗi Genesis() từ tệp Genesis.go của gói blockchain.

Bài viết tiếp theo sẽ nói về việc kết nối máy khách với một nút bằng cơ chế WebSocket.

Nguồn: www.habr.com

Thêm một lời nhận xét