区块链核心技术,leveldb使用

  • 晓道
  • 更新于 2022-03-20 14:39
  • 阅读 3712

区块链核心技术,leveldb使用,geth 中的应用

介绍

leveldb 是google开源的一个键值数据库,在区块链项目中得到广泛的使用。 如btc,eth各种项目都使用leveldb,算是区块链核心组件,所以我们讲讲leveldb的使用。

【深度知识】区块链数据库LevelDB从入门到原理详解

安装

go get github.com/syndtr/goleveldb/leveldb

根据我的经验,不少人在windows上会出现找不到gcc的error 需要自行安装gcc,这里可以下载tmd gcc 这个错误的原因是goleveldb 通过cgo的方式链接leveldb的c语言版本,需要在本地编译leveldb c lib。

使用

数据库打开

import "github.com/syndtr/goleveldb/leveldb"
func main() {
    db, err := leveldb.OpenFile("./test.db", nil)
    if err != nil {
        println(err)
    }
    defer db.Close()
}

运行结束会产生一个test.db的目录,这个目录里面存放了数据库文件。

读写数据

前面说到了,leveldb是一个键值数据库。 使用api基本和redis api差不多。

// 读取 键值
data, err := db.Get([]byte("key"), nil)
//写入 键值
err = db.Put([]byte("key"), []byte("value"), nil)
//删除 键值
err = db.Delete([]byte("key"), nil)

查询数据

遍历方式

iter := db.NewIterator(nil, nil)
    for iter.Next() {
        //从迭代器里读取 键和值
        key := iter.Key()
        value := iter.Value()
    }
    iter.Release() //要释放迭代器

范围遍历

iter2 := db.NewIterator(&util.Range{Start: []byte("1"), Limit: []byte("3")}, nil)

前缀遍历

iter3 := db.NewIterator(util.BytesPrefix([]byte("a-")), nil)

leveldb在geth中的使用

在最新版本的geth中 schema.go 明确了,数据库的key前缀

headerPrefix       = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
    headerTDSuffix     = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
    headerHashSuffix   = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
    headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)

    blockBodyPrefix     = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
    blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts

    txLookupPrefix        = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
    bloomBitsPrefix       = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
    SnapshotAccountPrefix = []byte("a") // SnapshotAccountPrefix + account hash -> account trie value
    SnapshotStoragePrefix = []byte("o") // SnapshotStoragePrefix + account hash + storage hash -> storage trie value
    CodePrefix            = []byte("c") // CodePrefix + code hash -> account code
    skeletonHeaderPrefix  = []byte("S") // skeletonHeaderPrefix + num (uint64 big endian) -> header

如我们要查找一个header,geth是怎么做的呢?

前缀查找方式,h-uint64(number)的方式

func encodeBlockNumber(number uint64) []byte {
    enc := make([]byte, 8)
    binary.BigEndian.PutUint64(enc, number)
    return enc
}

// headerKeyPrefix = headerPrefix + num (uint64 big endian)
func headerKeyPrefix(number uint64) []byte {
    return append(headerPrefix, encodeBlockNumber(number)...)
}
//查找一个header number里面的hash,前缀查找方式,h-uint64(number)的方式
func ReadAllHashes(db ethdb.Iteratee, number uint64) []common.Hash {
    prefix := headerKeyPrefix(number)

    hashes := make([]common.Hash, 0, 1)
    it := db.NewIterator(prefix, nil)
    defer it.Release()

    for it.Next() {
        if key := it.Key(); len(key) == len(prefix)+32 {
            hashes = append(hashes, common.BytesToHash(key[len(key)-32:]))
        }
    }
    return hashes
}

上面的代码,来自geth最新版的代码。

其他方式,请对照代码,基本就前面写的这几种方式。

点赞 2
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论
晓道
晓道
0xdD09...9161
技术交流:https://t.me/realDAO