dione/blockchain/pool/blockpool.go

162 lines
3.3 KiB
Go
Raw Normal View History

2021-05-14 20:32:49 +00:00
package pool
import (
"encoding/hex"
"errors"
types2 "github.com/Secured-Finance/dione/blockchain/types"
2021-05-14 20:32:49 +00:00
"github.com/fxamacker/cbor/v2"
2021-05-14 20:32:49 +00:00
"github.com/ledgerwatch/lmdb-go/lmdb"
)
const (
DefaultBlockPrefix = "block_"
DefaultBlockHeaderPrefix = "header_"
LatestBlockKey = "latest_block"
2021-05-14 20:32:49 +00:00
)
var (
ErrBlockNotFound = errors.New("block isn't found")
)
type BlockPool struct {
dbEnv *lmdb.Env
db lmdb.DBI
}
func NewBlockPool(path string) (*BlockPool, error) {
pool := &BlockPool{}
// configure lmdb env
env, err := lmdb.NewEnv()
if err != nil {
return nil, err
}
err = env.SetMapSize(100 * 1024 * 1024 * 1024) // 100 GB
if err != nil {
return nil, err
}
err = env.Open(path, 0, 0664)
if err != nil {
return nil, err
}
pool.dbEnv = env
var dbi lmdb.DBI
err = env.Update(func(txn *lmdb.Txn) error {
dbi, err = txn.OpenDBI("blocks", lmdb.Create)
return err
})
if err != nil {
return nil, err
}
pool.db = dbi
return pool, nil
}
func (bp *BlockPool) SetLatestBlock(hash []byte) error {
return bp.dbEnv.Update(func(txn *lmdb.Txn) error {
return txn.Put(bp.db, []byte(LatestBlockKey), hash, 0)
})
}
func (bp *BlockPool) GetLatestBlock() ([]byte, error) {
var hash []byte
err := bp.dbEnv.View(func(txn *lmdb.Txn) error {
data, err := txn.Get(bp.db, []byte(LatestBlockKey))
if err != nil {
if lmdb.IsNotFound(err) {
return nil
}
return err
}
hash = data
return nil
})
return hash, err
}
func (bp *BlockPool) StoreBlock(block *types2.Block) error {
2021-05-14 20:32:49 +00:00
return bp.dbEnv.Update(func(txn *lmdb.Txn) error {
data, err := cbor.Marshal(block)
if err != nil {
return err
}
headerData, err := cbor.Marshal(block.Header)
if err != nil {
return err
}
blockHash := hex.EncodeToString(block.Header.Hash)
err = txn.Put(bp.db, []byte(DefaultBlockPrefix+blockHash), data, 0)
if err != nil {
return err
}
err = txn.Put(bp.db, []byte(DefaultBlockHeaderPrefix+blockHash), headerData, 0) // store header separately for easy fetching
return err
})
}
func (bp *BlockPool) HasBlock(blockHash string) (bool, error) {
var blockExists bool
err := bp.dbEnv.View(func(txn *lmdb.Txn) error {
_, err := txn.Get(bp.db, []byte(DefaultBlockPrefix+blockHash)) // try to fetch block header
if err != nil {
if lmdb.IsNotFound(err) {
blockExists = false
return nil
}
return err
}
blockExists = true
return nil
})
if err != nil {
return false, err
}
return blockExists, nil
}
func (bp *BlockPool) FetchBlock(blockHash string) (*types2.Block, error) {
var block types2.Block
2021-05-14 20:32:49 +00:00
err := bp.dbEnv.View(func(txn *lmdb.Txn) error {
data, err := txn.Get(bp.db, []byte(DefaultBlockPrefix+blockHash))
if err != nil {
if lmdb.IsNotFound(err) {
return ErrBlockNotFound
}
return err
}
err = cbor.Unmarshal(data, &block)
return err
})
if err != nil {
return nil, err
}
return &block, nil
}
func (bp *BlockPool) FetchBlockHeader(blockHash string) (*types2.BlockHeader, error) {
var blockHeader types2.BlockHeader
2021-05-14 20:32:49 +00:00
err := bp.dbEnv.View(func(txn *lmdb.Txn) error {
data, err := txn.Get(bp.db, []byte(DefaultBlockHeaderPrefix+blockHash))
if err != nil {
if lmdb.IsNotFound(err) {
return ErrBlockNotFound
}
return err
}
err = cbor.Unmarshal(data, &blockHeader)
return err
})
if err != nil {
return nil, err
}
return &blockHeader, nil
}