区块链核心技术,leveldb使用,geth 中的应用
leveldb 是google开源的一个键值数据库,在区块链项目中得到广泛的使用。 如btc,eth各种项目都使用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)
在最新版本的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最新版的代码。
其他方式,请对照代码,基本就前面写的这几种方式。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!