From 2cd62d00799f0f5aa4ac20c4d04d641922329513 Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Fri, 14 May 2021 23:32:49 +0300 Subject: [PATCH] Implement basic blockpool --- go.mod | 1 + go.sum | 2 + pool/blockpool.go | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 pool/blockpool.go diff --git a/go.mod b/go.mod index a677663..a5e902f 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/jmoiron/sqlx v1.2.0 github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect github.com/klauspost/cpuid/v2 v2.0.6 // indirect + github.com/ledgerwatch/lmdb-go v1.17.8 // indirect github.com/libp2p/go-libp2p v0.12.0 github.com/libp2p/go-libp2p-core v0.7.0 github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb diff --git a/go.sum b/go.sum index b86294b..985b752 100644 --- a/go.sum +++ b/go.sum @@ -909,6 +909,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/ledgerwatch/lmdb-go v1.17.8 h1:IQUVJ2MYIfSsrhz+o+QbugUqRQuqTXodt8pE6cuvQVg= +github.com/ledgerwatch/lmdb-go v1.17.8/go.mod h1:NKRpCxksoTQPyxsUcBiVOe0135uqnJsnf6cElxmOL0o= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= diff --git a/pool/blockpool.go b/pool/blockpool.go new file mode 100644 index 0000000..b2c8ba1 --- /dev/null +++ b/pool/blockpool.go @@ -0,0 +1,137 @@ +package pool + +import ( + "encoding/hex" + "errors" + + "github.com/Secured-Finance/dione/types" + "github.com/fxamacker/cbor/v2" + "github.com/ledgerwatch/lmdb-go/lmdb" +) + +const ( + DefaultBlockPrefix = "block_" + DefaultBlockHeaderPrefix = "header_" +) + +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) StoreBlock(block *types.Block) error { + 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) (*types.Block, error) { + var block types.Block + 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) (*types.BlockHeader, error) { + var blockHeader types.BlockHeader + 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 +}