diff --git a/consensus/model/block.go b/consensus/model/block.go index 0e8d8ab3..395e049d 100644 --- a/consensus/model/block.go +++ b/consensus/model/block.go @@ -7,4 +7,6 @@ type Block interface { GetHash() *hash.Hash GetState() BlockState GetOrder() uint + HasParents() bool + GetMainParent() uint } diff --git a/consensus/model/block_chain.go b/consensus/model/block_chain.go index 418f8d8d..f46724ed 100644 --- a/consensus/model/block_chain.go +++ b/consensus/model/block_chain.go @@ -3,6 +3,7 @@ package model import ( "github.com/Qitmeer/qng/common/hash" "github.com/Qitmeer/qng/core/types" + "github.com/Qitmeer/qng/core/types/pow" ) type BlockChain interface { @@ -20,6 +21,9 @@ type BlockChain interface { Stop() error GetBlockByOrder(order uint64) Block GetBlockById(id uint) Block + GetMainChainTip() Block FetchBlockByHash(hash *hash.Hash) (*types.SerializedBlock, error) GetBlockOrderByHash(hash *hash.Hash) (uint, error) + GetBlockHeader(block Block) *types.BlockHeader + ForeachBlueBlocks(start Block, depth uint, powType pow.PowType, fn func(block Block, header *types.BlockHeader) error) error } diff --git a/core/blockchain/blockindex.go b/core/blockchain/blockindex.go index 0d967e34..4799a69b 100644 --- a/core/blockchain/blockindex.go +++ b/core/blockchain/blockindex.go @@ -7,6 +7,7 @@ import ( "github.com/Qitmeer/qng/consensus/forks" "github.com/Qitmeer/qng/consensus/model" "github.com/Qitmeer/qng/core/types" + "github.com/Qitmeer/qng/core/types/pow" "github.com/Qitmeer/qng/meerdag" ) @@ -59,6 +60,10 @@ func (b *BlockChain) GetBlockById(id uint) model.Block { return b.bd.GetBlockById(id) } +func (b *BlockChain) GetMainChainTip() model.Block { + return b.bd.GetMainChainTip() +} + // BlockOrderByHash returns the order of the block with the given hash in the // chain. // @@ -338,8 +343,9 @@ func (b *BlockChain) fetchHeaderByHash(hash *hash.Hash) (*types.BlockHeader, err return nil, fmt.Errorf("unable to find block header %v db %v", hash, err) } -func (b *BlockChain) GetBlockHeader(ib meerdag.IBlock) *types.BlockHeader { - if ib == nil { +func (b *BlockChain) GetBlockHeader(block model.Block) *types.BlockHeader { + ib, ok := block.(meerdag.IBlock) + if ib == nil || !ok { return nil } if ib.GetData() != nil { @@ -357,3 +363,16 @@ func (b *BlockChain) GetBlockHeader(ib meerdag.IBlock) *types.BlockHeader { } return header } + +func (b *BlockChain) ForeachBlueBlocks(start model.Block, depth uint, powType pow.PowType, fn func(block model.Block, header *types.BlockHeader) error) error { + return b.bd.Foreach(start.(meerdag.IBlock), depth, meerdag.Blue, func(block meerdag.IBlock) (bool, error) { + blockHeader := b.GetBlockHeader(block) + if blockHeader == nil { + return false, fmt.Errorf("No blockHeader:%s", block.GetHash().String()) + } + if blockHeader.Pow.GetPowType() != powType { + return false, nil + } + return true, fn(block, blockHeader) + }) +} diff --git a/meerdag/blocktransf.go b/meerdag/blocktransf.go index 5ac3b4f8..7226dda7 100644 --- a/meerdag/blocktransf.go +++ b/meerdag/blocktransf.go @@ -4,6 +4,20 @@ import ( "fmt" "github.com/Qitmeer/qng/common/hash" "sort" + "time" +) + +type FilterType byte + +const ( + // all + All FilterType = 0 + + // only blocks in blue set + Blue FilterType = 1 + + // only blocks in red set + Red FilterType = 2 ) // Is there a block in DAG? @@ -418,3 +432,60 @@ func (bd *MeerDAG) locateBlocksFuzzy(gs *GraphState, maxHashes uint) []*hash.Has func (bd *MeerDAG) GetLayer(id uint) uint { return bd.GetBlockById(id).GetLayer() } + +func (bd *MeerDAG) Foreach(start IBlock, depth uint, filter FilterType, fn func(block IBlock) (bool, error)) error { + if _, ok := bd.instance.(*Phantom); !ok { + return fmt.Errorf("Not support Foreach:%s", bd.instance.GetName()) + } + count := uint(0) + cost := time.Now() + cur := start + for count < depth && cur != nil { + if cur.GetID() != start.GetID() { + ret, err := fn(cur) + if err != nil { + return err + } + if ret { + count++ + if count >= depth { + break + } + } + } + if cur.GetID() == 0 { + break + } + das := cur.(*PhantomBlock).GetDiffAnticoneList(filter) + if len(das) > 0 { + for i := len(das) - 1; i >= 0; i-- { + if das[i] == MaxId { + continue + } + block := bd.GetBlockById(das[i]) + if block == nil { + return fmt.Errorf("No block:id=%d", das[i]) + } + pBlock := block.(*PhantomBlock) + ret, err := fn(pBlock) + if err != nil { + return err + } + if ret { + count++ + } + } + } + + mp := bd.GetBlockById(cur.GetMainParent()) + if mp == nil { + return fmt.Errorf("No block:id=%d", cur.GetMainParent()) + } + cur = mp + } + if count == 0 { + return nil + } + log.Trace("Foreach dag blocks", "count", count, "depth", depth, "time", time.Since(cost)) + return nil +} diff --git a/meerdag/pantomblock.go b/meerdag/pantomblock.go index 740677ea..39fcb4e4 100644 --- a/meerdag/pantomblock.go +++ b/meerdag/pantomblock.go @@ -162,6 +162,35 @@ func (pb *PhantomBlock) GetRedDiffAnticone() *IdSet { return pb.redDiffAnticone } +func (pb *PhantomBlock) GetDiffAnticoneList(filterType FilterType) []uint { + if pb.GetDiffAnticoneSize() <= 0 { + return nil + } + list := []uint{} + for i := 0; i < pb.GetDiffAnticoneSize(); i++ { + list = append(list, MaxId) + } + if filterType == Blue || + filterType == All { + if pb.GetBlueDiffAnticoneSize() > 0 { + for k, v := range pb.GetBlueDiffAnticone().GetMap() { + idx := v.(uint) - 1 + list[idx] = k + } + } + } + if filterType == Red || + filterType == All { + if pb.GetRedDiffAnticoneSize() > 0 { + for k, v := range pb.GetRedDiffAnticone().GetMap() { + idx := v.(uint) - 1 + list[idx] = k + } + } + } + return list +} + func (pb *PhantomBlock) GetBlueDiffAnticoneSize() int { if pb.blueDiffAnticone == nil { return 0 diff --git a/meerdag/test/phantom_test.go b/meerdag/test/phantom_test.go index d0ce8f22..89348a9d 100644 --- a/meerdag/test/phantom_test.go +++ b/meerdag/test/phantom_test.go @@ -456,3 +456,90 @@ func checkLoad(t *testing.T) { t.Fatal(err) } } + +func Test_ForeachFig1(t *testing.T) { + ibd := InitBlockDAG(meerdag.PHANTOM, "PH_fig1-blocks") + if ibd == nil { + t.FailNow() + } + ph := ibd.(*meerdag.Phantom) + order := []uint{bd.GetMainChainTip().GetID()} + + ph.UpdateVirtualBlockOrder() + + err := bd.Foreach(bd.GetMainChainTip(), meerdag.MaxId, meerdag.All, func(block meerdag.IBlock) (bool, error) { + t.Logf("block id:%d hash:%s order:%d", block.GetID(), block.GetHash().String(), block.GetOrder()) + order = append(order, block.GetID()) + return true, nil + }) + if err != nil { + t.Fatal(err) + } + order = reverseBlockList(order) + target := changeToIDList(testData.PH_OrderFig1.Output) + for i := 0; i < len(order); i++ { + if order[i] != target[i] { + t.FailNow() + } + } + fmt.Printf("The Fig.1 Order from mainTip: ") + printBlockChainTag(order) +} + +func Test_ForeachFig2(t *testing.T) { + ibd := InitBlockDAG(meerdag.PHANTOM, "PH_fig2-blocks") + if ibd == nil { + t.FailNow() + } + ph := ibd.(*meerdag.Phantom) + order := []uint{bd.GetMainChainTip().GetID()} + + ph.UpdateVirtualBlockOrder() + + err := bd.Foreach(bd.GetMainChainTip(), meerdag.MaxId, meerdag.All, func(block meerdag.IBlock) (bool, error) { + t.Logf("block id:%d hash:%s order:%d", block.GetID(), block.GetHash().String(), block.GetOrder()) + order = append(order, block.GetID()) + return true, nil + }) + if err != nil { + t.Fatal(err) + } + order = reverseBlockList(order) + target := changeToIDList(testData.PH_OrderFig2.Output) + for i := 0; i < len(order); i++ { + if order[i] != target[i] { + t.FailNow() + } + } + fmt.Printf("The Fig.1 Order from mainTip: ") + printBlockChainTag(order) +} + +func Test_ForeachFig4(t *testing.T) { + ibd := InitBlockDAG(meerdag.PHANTOM, "PH_fig4-blocks") + if ibd == nil { + t.FailNow() + } + ph := ibd.(*meerdag.Phantom) + order := []uint{bd.GetMainChainTip().GetID()} + + ph.UpdateVirtualBlockOrder() + + err := bd.Foreach(bd.GetMainChainTip(), meerdag.MaxId, meerdag.All, func(block meerdag.IBlock) (bool, error) { + t.Logf("block id:%d hash:%s order:%d", block.GetID(), block.GetHash().String(), block.GetOrder()) + order = append(order, block.GetID()) + return true, nil + }) + if err != nil { + t.Fatal(err) + } + order = reverseBlockList(order) + target := changeToIDList(testData.PH_OrderFig4.Output) + for i := 0; i < len(order); i++ { + if order[i] != target[i] { + t.FailNow() + } + } + fmt.Printf("The Fig.1 Order from mainTip: ") + printBlockChainTag(order) +}