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  }