記事ディレクトリ
リンク: ブロックチェーン プロジェクトの github アドレス
プロジェクトの現在の進行状況:
ボルトデータベースのインストール
ボルトデータベースの紹介:
ボルト データベースは Go 言語用に提供されている軽量のデータセットで、
[]byte にデータが格納されるシンプルで高速なリレーショナル データベースです。インデックス作成方法はキー/値メソッドです。つまり、データはキーワードによってインデックス付けされます。
Bolt プロジェクト アドレス:リンク
インストール手順:
1. プロジェクト アドレスの下のターミナルで実行します。
go get github.com/boltdb/bolt/...
2. 現在のプロジェクトの .mod ファイルにステートメントを追加します。
require (
github.com/boltdb/bolt v1.3.1 // indirect
golang.org/x/sys v0.3.0 // indirect
)
3. MOD ファイルを変更した後、次のコマンドを実行する必要があります。
go mod vendor
アップデート
永続的なストレージにはボルトを使用する
以前のブロックチェーン プログラムと比較すると、永続ストレージを使用することは、保存と永続性のためにブロックチェーンをデータベースに保存することを意味します。以前の非永続化プログラムと比較すると、変更点は次のとおりです。
1. ジェネシス ブロックを永続化する
2. 新しいブロックを永続化する
ボルトの耐久性の基本手順
1. データベースを作成または開きます。dbName はデータベースの名前です。0600 はデータベースの権限を示します (0600 のバイナリ コードは 111,000,000 で、管理者には読み取りおよび書き込み権限があるが、実行権限がないことを示します)。nil はデータベースの権限を示します。デフォルトの操作
db, err := bolt.Open(dbName, 0600, nil)
2. データベース上にデータテーブルを作成する操作を実行します。バケットはデータテーブルの意味です。
db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blockTableName))
if b == nil {
//数据表不存在
b, err := tx.CreateBucket([]byte(blockTableName))
if err != nil {
log.Panicf("create backet [%s] failed %v\n", blockTableName, err)
}
}
return nil
})
3. データの追加および挿入操作。b.get はキーを使用して値にインデックスを付けることを意味し、取得された値は []byte の形式になります。b.put は値を格納することを意味し、データはキーと値のペアの形式。
bc.DB.Update(func(tx *bolt.Tx) error {
//获取数据库桶
b := tx.Bucket([]byte(blockTableName))
if b != nil {
blockTypes := b.Get(bc.Tip)
err = b.Put([]byte("l"), newBlock.Hash)
if err != nil {
log.Panicf("save the latest block hash failed %v\n", err)
}
}
return nil
})
ジェネシスブロックの永続性
本来のやり方:
func CreateBlockChainWithGenesisBlock() *BlockChain {
//生成创世区块
block := CreateGenesisBlock([]byte("the first block"))
return &BlockChain{
[]*Block{
block}}
}
// 生成创世区块
func CreateGenesisBlock(data []byte) *Block {
return NewBlock(nil, 1, data)
}
永続化方法:
db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blockTableName))
if b == nil {
//数据表不存在
b, err := tx.CreateBucket([]byte(blockTableName))
if err != nil {
log.Panicf("create backet [%s] failed %v\n", blockTableName, err)
}
//生成创世区块
genesisBlock := CreateGenesisBlock([]byte("the first block"))
//键为区块的哈希,值为区块的序列化
err = b.Put(genesisBlock.Hash, genesisBlock.Serialize())
if err != nil {
log.Panicf("insert the genesis block failed %v\n", err)
}
blockHash = genesisBlock.Hash
//数据库中也存储最新区块的哈希
err = b.Put([]byte("l"), genesisBlock.Hash)
if err != nil {
log.Panicf("save the latest hash of genesis block failed %v\n", err)
}
} else {
//数据表已存在
blockHash = b.Get([]byte("l"))
}
return nil
})
if err != nil {
log.Panicf("create db [%s] failed %v\n", dbName, err)
}
新しいブロックの永続化
本来のやり方:
func (bc *BlockChain) AddBlock(prevBlockHash []byte, height int64, data []byte) {
var newBlock *Block
newBlock = NewBlock(prevBlockHash, height, data)
bc.Blocks = append(bc.Blocks, newBlock)
}
永続化方法:
bc.DB.Update(func(tx *bolt.Tx) error {
//获取数据库桶
b := tx.Bucket([]byte(blockTableName))
if b != nil {
//获取对应区块
blockTypes := b.Get(bc.Tip)
//区块结构反序列化
latestBlock := DeserializeBlock(blockTypes)
//新建区块,传入参数:prevBlockHash []byte, height int64, data []byte
newBlock := NewBlock(latestBlock.Hash, latestBlock.Height+1, data)
//存入数据库
bc.Tip = newBlock.Hash
err := b.Put(newBlock.Hash, newBlock.Serialize())
if err != nil {
log.Panicf("insert the new block failed %v\n", err)
}
err = b.Put([]byte("l"), newBlock.Hash)
if err != nil {
log.Panicf("save the latest block hash failed %v\n", err)
}
}
return nil
})
ブロックチェーンの基本機能を向上させる
ブロックチェーンは削除や変更をサポートしていないため、現在のプロジェクトのブロックチェーンの機能はジェネシスブロックの作成、ブロックの追加、ブロックチェーンの横断などですが、将来的には取引情報やマイニングなど複数の機能を改善する予定です。 。以前の機能と比較して、改善された点は次のとおりです。 1. 永続性、 2. 新しいトラバーサル関数、 3. 新しいイテレータ
ジェネシスブロックの作成
構造をシリアル化することで、(ブロック ハッシュ –> ブロック情報) によってブロックをデータベースに保存できるため、後で前のブロックのハッシュを取得した後、前のブロックのインデックス付けが容易になります。
// 初始化区块链
func CreateBlockChainWithGenesisBlock() *BlockChain {
//存储最新区块链哈希
var blockHash []byte
//1.创建或打开一个数据库
db, err := bolt.Open(dbName, 0600, nil)
//2.创建一个桶,将创世区块存入数据库中
db.Update(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blockTableName))
if b == nil {
//数据表不存在
b, err := tx.CreateBucket([]byte(blockTableName))
if err != nil {
log.Panicf("create backet [%s] failed %v\n", blockTableName, err)
}
//生成创世区块
genesisBlock := CreateGenesisBlock([]byte("the first block"))
//键为区块的哈希,值为区块的序列化
err = b.Put(genesisBlock.Hash, genesisBlock.Serialize())
if err != nil {
log.Panicf("insert the genesis block failed %v\n", err)
}
blockHash = genesisBlock.Hash
//数据库中也存储最新区块的哈希
err = b.Put([]byte("l"), genesisBlock.Hash)
if err != nil {
log.Panicf("save the latest hash of genesis block failed %v\n", err)
}
}
return nil
})
if err != nil {
log.Panicf("create db [%s] failed %v\n", dbName, err)
}
return &BlockChain{
DB: db, Tip: blockHash}
}
ブロックのシリアル化コード:
// 区块结构序列化,结构体->字节数组
func (block *Block) Serialize() []byte {
var buffer bytes.Buffer
//序列化结构体
encoder := gob.NewEncoder(&buffer)
err := encoder.Encode(block)
if err != nil {
log.Panicf("serialize the block to byte[] failed %v", err)
}
return buffer.Bytes()
}
ブロック逆シリアル化コード
// 区块结构反序列化,字节数组->结构体
func DeserializeBlock(blockByte []byte) *Block {
var block Block
decoder := gob.NewDecoder(bytes.NewReader(blockByte))
err := decoder.Decode(&block)
if err != nil {
log.Panicf("deserialize the byte[] to block failed %v", err)
}
return &block
}
ブロックを追加する
func (bc *BlockChain) AddBlock(data []byte) {
//更新区块数据(insert)
bc.DB.Update(func(tx *bolt.Tx) error {
//获取数据库桶
b := tx.Bucket([]byte(blockTableName))
if b != nil {
//获取对应区块
blockTypes := b.Get(bc.Tip)
//区块结构反序列化
latestBlock := DeserializeBlock(blockTypes)
//新建区块,传入参数:prevBlockHash []byte, height int64, data []byte
newBlock := NewBlock(latestBlock.Hash, latestBlock.Height+1, data)
//存入数据库
bc.Tip = newBlock.Hash
err := b.Put(newBlock.Hash, newBlock.Serialize())
if err != nil {
log.Panicf("insert the new block failed %v\n", err)
}
err = b.Put([]byte("l"), newBlock.Hash)
if err != nil {
log.Panicf("save the latest block hash failed %v\n", err)
}
}
return nil
})
}
ブロックチェーンを横断する
ここでは、イテレータを使用してブロックチェーンを最適化し、コードの可読性を向上させます。
func (bc *BlockChain) PrintBlockChain() {
var curBlock *Block
var iter *BlockChainIterator = bc.Iterator()
fmt.Printf("打印区块链完整信息。。。\n")
//循环读取
for {
curBlock = iter.Next()
fmt.Printf("-------------------------------------------\n")
fmt.Printf("\tHash : %x\n", curBlock.Hash)
fmt.Printf("\tPrevBlockHash : %x\n", curBlock.PrevBlockHash)
fmt.Printf("\tHeight : %x\n", curBlock.Height)
fmt.Printf("\tData : %v\n", curBlock.Data)
fmt.Printf("\tNonce : %x\n", curBlock.Nonce)
fmt.Printf("\tTimeStamp : %x\n", curBlock.TimeStamp)
//退出条件,由于哈希值的大数特性,需要使用函数进行比较
var hashInt big.Int
hashInt.SetBytes(iter.curHash)
if big.NewInt(0).Cmp(&hashInt) == 0 {
//遍历到了创世区块
break
}
}
イテレータは次のように実装されます。
// 实现迭代函数next()
func (iter *BlockChainIterator) Next() *Block {
var curBlock *Block
err := iter.DB.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(blockTableName))
if b != nil {
Block := b.Get(iter.curHash)
curBlock = DeserializeBlock(Block)
//更新迭代器当前指向结点哈希
iter.curHash = curBlock.PrevBlockHash
}
return nil
})
if err != nil {
log.Panicf("Iterator the db failed%v\n", err)
} else {
return curBlock
}
return nil
}