const logModule = "leveldb"
var (
- BlockStoreKey = []byte("blockStore")
- BlockPrefix = []byte("B:")
- BlockHeaderPrefix = []byte("BH:")
- TxStatusPrefix = []byte("BTS:")
+ blockStoreKey = []byte("blockStore")
+ blockPrefix = []byte("B:")
+ blockHeaderPrefix = []byte("BH:")
+ txStatusPrefix = []byte("BTS:")
)
func loadBlockStoreStateJSON(db dbm.DB) *protocol.BlockStoreState {
- bytes := db.Get(BlockStoreKey)
+ bytes := db.Get(blockStoreKey)
if bytes == nil {
return nil
}
cache blockCache
}
-func CalcBlockKey(hash *bc.Hash) []byte {
- return append(BlockPrefix, hash.Bytes()...)
+func calcBlockKey(hash *bc.Hash) []byte {
+ return append(blockPrefix, hash.Bytes()...)
}
-func CalcBlockHeaderKey(height uint64, hash *bc.Hash) []byte {
+func calcBlockHeaderKey(height uint64, hash *bc.Hash) []byte {
buf := [8]byte{}
binary.BigEndian.PutUint64(buf[:], height)
- key := append(BlockHeaderPrefix, buf[:]...)
+ key := append(blockHeaderPrefix, buf[:]...)
return append(key, hash.Bytes()...)
}
-func CalcTxStatusKey(hash *bc.Hash) []byte {
- return append(TxStatusPrefix, hash.Bytes()...)
+func calcTxStatusKey(hash *bc.Hash) []byte {
+ return append(txStatusPrefix, hash.Bytes()...)
}
// GetBlock return the block by given hash
func GetBlock(db dbm.DB, hash *bc.Hash) (*types.Block, error) {
- bytez := db.Get(CalcBlockKey(hash))
+ bytez := db.Get(calcBlockKey(hash))
if bytez == nil {
return nil, nil
}
// GetTransactionStatus will return the utxo that related to the block hash
func (s *Store) GetTransactionStatus(hash *bc.Hash) (*bc.TransactionStatus, error) {
- data := s.db.Get(CalcTxStatusKey(hash))
+ data := s.db.Get(calcTxStatusKey(hash))
if data == nil {
return nil, errors.New("can't find the transaction status by given hash")
}
func (s *Store) LoadBlockIndex(stateBestHeight uint64) (*state.BlockIndex, error) {
startTime := time.Now()
blockIndex := state.NewBlockIndex()
- bhIter := s.db.IteratorPrefix(BlockHeaderPrefix)
+ bhIter := s.db.IteratorPrefix(blockHeaderPrefix)
defer bhIter.Release()
var lastNode *state.BlockNode
blockHash := block.Hash()
batch := s.db.NewBatch()
- batch.Set(CalcBlockKey(&blockHash), binaryBlock)
- batch.Set(CalcBlockHeaderKey(block.Height, &blockHash), binaryBlockHeader)
- batch.Set(CalcTxStatusKey(&blockHash), binaryTxStatus)
+ batch.Set(calcBlockKey(&blockHash), binaryBlock)
+ batch.Set(calcBlockHeaderKey(block.Height, &blockHash), binaryBlockHeader)
+ batch.Set(calcTxStatusKey(&blockHash), binaryTxStatus)
batch.Write()
log.WithFields(log.Fields{
return err
}
- batch.Set(BlockStoreKey, bytes)
+ batch.Set(blockStoreKey, bytes)
batch.Write()
return nil
}
t.Errorf("got status:%v, expect status:%v", gotStatus, status)
}
- data := store.db.Get(CalcBlockHeaderKey(block.Height, &blockHash))
+ data := store.db.Get(calcBlockHeaderKey(block.Height, &blockHash))
gotBlockHeader := types.BlockHeader{}
if err := gotBlockHeader.UnmarshalText(data); err != nil {
t.Fatal(err)
dbm "github.com/bytom/database/leveldb"
)
-const UtxoPreFix = "UT:"
+const utxoPreFix = "UT:"
-func CalcUtxoKey(hash *bc.Hash) []byte {
- return []byte(UtxoPreFix + hash.String())
+func calcUtxoKey(hash *bc.Hash) []byte {
+ return []byte(utxoPreFix + hash.String())
}
func getTransactionsUtxo(db dbm.DB, view *state.UtxoViewpoint, txs []*bc.Tx) error {
continue
}
- data := db.Get(CalcUtxoKey(&prevout))
+ data := db.Get(calcUtxoKey(&prevout))
if data == nil {
continue
}
func getUtxo(db dbm.DB, hash *bc.Hash) (*storage.UtxoEntry, error) {
var utxo storage.UtxoEntry
- data := db.Get(CalcUtxoKey(hash))
+ data := db.Get(calcUtxoKey(hash))
if data == nil {
return nil, errors.New("can't find utxo in db")
}
func saveUtxoView(batch dbm.Batch, view *state.UtxoViewpoint) error {
for key, entry := range view.Entries {
if entry.Spent && !entry.IsCoinBase {
- batch.Delete(CalcUtxoKey(&key))
+ batch.Delete(calcUtxoKey(&key))
continue
}
if err != nil {
return errors.Wrap(err, "marshaling utxo entry")
}
- batch.Set(CalcUtxoKey(&key), b)
+ batch.Set(calcUtxoKey(&key), b)
}
return nil
}
"github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
- "github.com/bytom/testutil"
)
var (
return prevOrphans, ok
}
-func (o *OrphanManage) Equals(o1 *OrphanManage) bool {
- if o1 == nil {
- return false
- }
-
- if !testutil.DeepEqual(o.orphan, o1.orphan) {
- return false
- }
-
- return testutil.DeepEqual(o.prevOrphans, o1.prevOrphans)
-}
-
func (o *OrphanManage) delete(hash *bc.Hash) {
block, ok := o.orphan[*hash]
if !ok {
// NewChain returns a new Chain using store as the underlying storage.
func NewChain(store Store, txPool *TxPool) (*Chain, error) {
- return NewChainWithOrphanManage(store, txPool, NewOrphanManage())
-}
-
-func NewChainWithOrphanManage(store Store, txPool *TxPool, manage *OrphanManage) (*Chain, error) {
c := &Chain{
- orphanManage: manage,
+ orphanManage: NewOrphanManage(),
txPool: txPool,
store: store,
processBlockCh: make(chan *processBlockMsg, maxProcessBlockChSize),
return node.CalcNextBits(), nil
}
-func (c *Chain) GetBlockIndex() *state.BlockIndex {
- return c.index
-}
-
// This function must be called with mu lock in above level
func (c *Chain) setState(node *state.BlockNode, view *state.UtxoViewpoint) error {
if err := c.store.SaveChainStatus(node, view); err != nil {
"github.com/bytom/consensus/difficulty"
"github.com/bytom/protocol/bc"
"github.com/bytom/protocol/bc/types"
- "github.com/bytom/testutil"
)
// approxNodesPerDay is an approximation of the number of new blocks there are
}
}
-func NewBlockIndexWithInitData(index map[bc.Hash]*BlockNode, mainChain []*BlockNode) *BlockIndex {
- return &BlockIndex{index:index, mainChain:mainChain}
-}
-
// AddNode will add node to the index map
func (bi *BlockIndex) AddNode(node *BlockNode) {
bi.Lock()
node = node.Parent
}
}
-
-func (bi *BlockIndex) Equals(bi1 *BlockIndex) bool {
- if bi1 == nil {
- return false
- }
-
- if !testutil.DeepEqual(bi.index, bi1.index) {
- return false
- }
- return testutil.DeepEqual(bi.mainChain, bi1.mainChain)
-}
+++ /dev/null
-package integration
-
-import (
- "testing"
-
- "github.com/bytom/config"
- "github.com/bytom/database"
- "github.com/bytom/database/storage"
- "github.com/bytom/protocol"
- "github.com/bytom/protocol/bc"
- "github.com/bytom/protocol/bc/types"
- "github.com/bytom/protocol/state"
-)
-
-func TestProcessBlock(t *testing.T) {
- gensisBlock := config.GenesisBlock()
- genesisBlockHash := gensisBlock.Hash()
- fillTransactionSize(gensisBlock)
-
- cases := []*processBlockTestCase{
- {
- desc: "process a invalid block",
- newBlock: &types.Block{
- BlockHeader: types.BlockHeader{
- Height: 1,
- Version: 1,
- PreviousBlockHash: genesisBlockHash,
- },
- },
- wantStore: storeItems{
- {
- key: database.BlockStoreKey,
- val: &protocol.BlockStoreState{Height: 0, Hash: &genesisBlockHash},
- },
- {
- key: database.CalcBlockKey(&genesisBlockHash),
- val: gensisBlock,
- },
- {
- key: database.CalcTxStatusKey(&genesisBlockHash),
- val: &bc.TransactionStatus{Version: 1, VerifyStatus: []*bc.TxVerifyResult{{StatusFail: false}}},
- },
- {
- key: database.CalcBlockHeaderKey(gensisBlock.Height, &genesisBlockHash),
- val: gensisBlock.BlockHeader,
- },
- {
- key: database.CalcUtxoKey(gensisBlock.Transactions[0].Tx.ResultIds[0]),
- val: &storage.UtxoEntry{IsCoinBase: true, BlockHeight: 0, Spent: false},
- },
- },
- wantBlockIndex: state.NewBlockIndexWithInitData(
- map[bc.Hash]*state.BlockNode{
- genesisBlockHash: mustNewBlockNode(&gensisBlock.BlockHeader, nil),
- },
- []*state.BlockNode{
- mustNewBlockNode(&gensisBlock.BlockHeader, nil),
- },
- ),
- wantOrphanManage: protocol.NewOrphanManage(),
- wantError: true,
- },
- }
-
- for _, c := range cases {
- if err := c.Run(); err != nil {
- panic(err)
- }
- }
-}
-
-func mustNewBlockNode(h *types.BlockHeader, parent *state.BlockNode) *state.BlockNode {
- node, err := state.NewBlockNode(h, parent)
- if err != nil {
- panic(err)
- }
- return node
-}
-
-func fillTransactionSize(block *types.Block) {
- for _, tx := range block.Transactions {
- bytes, err := tx.MarshalText()
- if err != nil {
- panic(err)
- }
- tx.TxData.SerializedSize = uint64(len(bytes) / 2)
- tx.Tx.SerializedSize = uint64(len(bytes) / 2)
- }
-}
+++ /dev/null
-package integration
-
-import (
- "encoding/json"
- "fmt"
- "os"
- "reflect"
- "strings"
-
- "github.com/golang/protobuf/proto"
-
- "github.com/bytom/database"
- dbm "github.com/bytom/database/leveldb"
- "github.com/bytom/database/storage"
- "github.com/bytom/event"
- "github.com/bytom/protocol"
- "github.com/bytom/protocol/bc"
- "github.com/bytom/protocol/bc/types"
- "github.com/bytom/protocol/state"
- "github.com/bytom/testutil"
-)
-
-const (
- dbDir = "temp"
-)
-
-type storeItem struct {
- key []byte
- val interface{}
-}
-
-type serialFun func(obj interface{}) ([]byte, error)
-type deserialFun func(data []byte) (interface{}, error)
-
-func getSerialFun(item interface{}) (serialFun, error) {
- switch item.(type) {
- case *protocol.BlockStoreState:
- return json.Marshal, nil
- case *types.Block:
- return func(obj interface{}) ([]byte, error) {
- block := obj.(*types.Block)
- return block.MarshalText()
- }, nil
- case types.BlockHeader:
- return func(obj interface{}) ([]byte, error) {
- bh := obj.(types.BlockHeader)
- return bh.MarshalText()
- }, nil
- case *bc.TransactionStatus:
- return func(obj interface{}) ([]byte, error) {
- status := obj.(*bc.TransactionStatus)
- return proto.Marshal(status)
- }, nil
- case *storage.UtxoEntry:
- return func(obj interface{}) ([]byte, error) {
- utxo := obj.(*storage.UtxoEntry)
- return proto.Marshal(utxo)
- }, nil
- }
- typ := reflect.TypeOf(item)
- return nil, fmt.Errorf("can not found any serialization function for type:%s", typ.Name())
-}
-
-func getDeserailFun(key []byte) (deserialFun, error) {
- funMap := map[string]deserialFun{
- string(database.BlockStoreKey): func(data []byte) (interface{}, error) {
- storeState := &protocol.BlockStoreState{}
- err := json.Unmarshal(data, storeState)
- return storeState, err
- },
- string(database.TxStatusPrefix): func(data []byte) (interface{}, error) {
- status := &bc.TransactionStatus{}
- err := proto.Unmarshal(data, status)
- return status, err
- },
- string(database.BlockPrefix): func(data []byte) (interface{}, error) {
- block := &types.Block{}
- err := block.UnmarshalText(data)
- return block, err
- },
- string(database.BlockHeaderPrefix): func(data []byte) (interface{}, error) {
- bh := types.BlockHeader{}
- err := bh.UnmarshalText(data)
- return bh, err
- },
- database.UtxoPreFix: func(data []byte) (interface{}, error) {
- utxo := &storage.UtxoEntry{}
- err := proto.Unmarshal(data, utxo)
- return utxo, err
- },
- }
-
- for prefix, converter := range funMap {
- if strings.HasPrefix(string(key), prefix) {
- return converter, nil
- }
- }
- return nil, fmt.Errorf("can not found any deserialization function for key:%s", string(key))
-}
-
-type storeItems []*storeItem
-
-func (s1 storeItems) equals(s2 storeItems) bool {
- if s2 == nil {
- return false
- }
-
- itemMap1 := make(map[string]interface{}, len(s1))
- for _, item := range s1 {
- itemMap1[string(item.key)] = item.val
- }
-
- itemMap2 := make(map[string]interface{}, len(s2))
- for _, item := range s2 {
- itemMap2[string(item.key)] = item.val
- }
-
- return testutil.DeepEqual(itemMap1, itemMap2)
-}
-
-type processBlockTestCase struct {
- desc string
- initStore []*storeItem
- wantStore []*storeItem
- wantBlockIndex *state.BlockIndex
- initOrphanManage *protocol.OrphanManage
- wantOrphanManage *protocol.OrphanManage
- wantIsOrphan bool
- wantError bool
- newBlock *types.Block
-}
-
-func (p *processBlockTestCase) Run() error {
- defer os.RemoveAll(dbDir)
- if p.initStore == nil {
- p.initStore = make([]*storeItem, 0)
- }
- store, db, err := initStore(p)
- if err != nil {
- return err
- }
-
- orphanManage := p.initOrphanManage
- if orphanManage == nil {
- orphanManage = protocol.NewOrphanManage()
- }
-
- txPool := protocol.NewTxPool(store, event.NewDispatcher())
- chain, err := protocol.NewChainWithOrphanManage(store, txPool, orphanManage)
- if err != nil {
- return err
- }
-
- isOrphan, err := chain.ProcessBlock(p.newBlock)
- if p.wantError != (err != nil) {
- return fmt.Errorf("#case(%s) want error:%t, got error:%t", p.desc, p.wantError, err != nil)
- }
-
- if isOrphan != p.wantIsOrphan {
- return fmt.Errorf("#case(%s) want orphan:%t, got orphan:%t", p.desc, p.wantIsOrphan, isOrphan)
- }
-
- if p.wantStore != nil {
- gotStoreItems, err := loadStoreItems(db)
- if err != nil {
- return err
- }
-
- if !storeItems(gotStoreItems).equals(p.wantStore) {
- return fmt.Errorf("#case(%s) want store:%v, got store:%v", p.desc, p.wantStore, gotStoreItems)
- }
- }
-
- if p.wantBlockIndex != nil {
- blockIndex := chain.GetBlockIndex()
- if !blockIndex.Equals(p.wantBlockIndex) {
- return fmt.Errorf("#case(%s) want block index:%v, got block index:%v", p.desc, *p.wantBlockIndex, *blockIndex)
- }
- }
-
- if p.wantOrphanManage != nil {
- if !orphanManage.Equals(p.wantOrphanManage) {
- return fmt.Errorf("#case(%s) want orphan manage:%v, got orphan manage:%v", p.desc, *p.wantOrphanManage, *orphanManage)
- }
- }
- return nil
-}
-
-func loadStoreItems(db dbm.DB) ([]*storeItem, error) {
- iter := db.Iterator()
- defer iter.Release()
-
- var items []*storeItem
- for iter.Next() {
- item := &storeItem{key: iter.Key()}
- fun, err := getDeserailFun(iter.Key())
- if err != nil {
- return nil, err
- }
-
- val, err := fun(iter.Value())
- if err != nil {
- return nil, err
- }
-
- item.val = val
- items = append(items, item)
- }
- return items, nil
-}
-
-func initStore(c *processBlockTestCase) (protocol.Store, dbm.DB, error) {
- testDB := dbm.NewDB("testdb", "leveldb", dbDir)
- batch := testDB.NewBatch()
- for _, item := range c.initStore {
- fun, err := getSerialFun(item.val)
- if err != nil {
- return nil, nil, err
- }
-
- bytes, err := fun(item.val)
- if err != nil {
- return nil, nil, err
- }
-
- batch.Set(item.key, bytes)
- }
- batch.Write()
- return database.NewStore(testDB), testDB, nil
-}