github.com/prysmaticlabs/prysm@v1.4.4/tools/blocktree/main.go (about) 1 /** 2 * Block tree graph viz 3 * 4 * Given a DB, start slot and end slot. This tool computes the graphviz data 5 * needed to construct the block tree in graphviz data format. Then one can paste 6 * the data in a Graph rendering engine (ie. http://www.webgraphviz.com/) to see the visual format. 7 8 */ 9 package main 10 11 import ( 12 "context" 13 "encoding/hex" 14 "flag" 15 "fmt" 16 "strconv" 17 18 "github.com/emicklei/dot" 19 types "github.com/prysmaticlabs/eth2-types" 20 "github.com/prysmaticlabs/prysm/beacon-chain/db" 21 "github.com/prysmaticlabs/prysm/beacon-chain/db/filters" 22 "github.com/prysmaticlabs/prysm/beacon-chain/db/kv" 23 "github.com/prysmaticlabs/prysm/shared/bytesutil" 24 ) 25 26 var ( 27 // Required fields 28 datadir = flag.String("datadir", "", "Path to data directory.") 29 startSlot = flag.Uint("startSlot", 0, "Start slot of the block tree") 30 endSlot = flag.Uint("endSlot", 0, "Start slot of the block tree") 31 ) 32 33 // Used for tree, each node is a representation of a node in the graph 34 type node struct { 35 parentRoot [32]byte 36 dothNode *dot.Node 37 score map[uint64]bool 38 } 39 40 func main() { 41 flag.Parse() 42 db, err := db.NewDB(context.Background(), *datadir, &kv.Config{}) 43 if err != nil { 44 panic(err) 45 } 46 47 graph := dot.NewGraph(dot.Directed) 48 graph.Attr("rankdir", "RL") 49 graph.Attr("labeljust", "l") 50 51 startSlot := types.Slot(*startSlot) 52 endSlot := types.Slot(*endSlot) 53 filter := filters.NewFilter().SetStartSlot(startSlot).SetEndSlot(endSlot) 54 blks, roots, err := db.Blocks(context.Background(), filter) 55 if err != nil { 56 panic(err) 57 } 58 59 // Construct nodes 60 m := make(map[[32]byte]*node) 61 for i := 0; i < len(blks); i++ { 62 b := blks[i] 63 r := roots[i] 64 m[r] = &node{score: make(map[uint64]bool)} 65 66 state, err := db.State(context.Background(), r) 67 if err != nil { 68 panic(err) 69 } 70 slot := b.Block().Slot() 71 // If the state is not available, roll back 72 for state == nil { 73 slot-- 74 _, rts, err := db.BlockRootsBySlot(context.Background(), slot) 75 if err != nil { 76 panic(err) 77 } 78 state, err = db.State(context.Background(), rts[0]) 79 if err != nil { 80 panic(err) 81 } 82 } 83 84 // Construct label of each node. 85 rStr := hex.EncodeToString(r[:2]) 86 label := "slot: " + strconv.Itoa(int(b.Block().Slot())) + "\n root: " + rStr 87 88 dotN := graph.Node(rStr).Box().Attr("label", label) 89 n := &node{ 90 parentRoot: bytesutil.ToBytes32(b.Block().ParentRoot()), 91 dothNode: &dotN, 92 } 93 m[r] = n 94 } 95 96 // Construct an edge only if block's parent exist in the tree. 97 for _, n := range m { 98 if _, ok := m[n.parentRoot]; ok { 99 graph.Edge(*n.dothNode, *m[n.parentRoot].dothNode) 100 } 101 } 102 103 fmt.Println(graph.String()) 104 }