func (b *BlockDAG) RenderDot() ([]byte, error) {
	var dot bytes.Buffer
	smallHashLen := 7
	graphIndex := make(map[string]int)
	n := 0
	_, err := fmt.Fprintln(&dot, "digraph dag {")
	if err != nil {
		return dot.Bytes(), err
	}
	_, err = fmt.Fprintln(&dot, "ordering=out;")
	if err != nil {
		return dot.Bytes(), err
	}
	dagState := b.DAGSnapshot()
	for height := int32(0); height <= dagState.MaxHeight; height++ {
		blocks, err := b.BlocksByHeight(height)
		if err != nil {
			return dot.Bytes(), err
		}
		for _, block := range blocks {
			hash := block.Hash().String()
			smallHashIndex := len(hash) - smallHashLen
			graphIndex[hash] = n
			_, err = fmt.Fprintf(&dot, "n%d [label=\"%s\", tooltip=\"height %d hash %s\"];\n",
				n, hash[smallHashIndex:], height, hash)
			if err != nil {
				return dot.Bytes(), err
			}
			n++
		}
	}
	for height := int32(0); height <= dagState.MaxHeight; height++ {
		blocks, err := b.BlocksByHeight(height)
		if err != nil {
			return dot.Bytes(), err
		}
		for _, block := range blocks {
			hash := block.Hash().String()
			blockN, inGraph := graphIndex[hash]
			if !inGraph {
				continue
			}
			for _, parent := range block.MsgBlock().Parents.Parents {
				parentN, inGraph := graphIndex[parent.Hash.String()]
				if !inGraph {
					return dot.Bytes(), fmt.Errorf("RenderDot block %s parent %s not in dot graph",
						block.Hash(), parent.Hash)
				}
				_, err := fmt.Fprintf(&dot, "n%d -> n%d;\n", blockN, parentN)
				if err != nil {
					return dot.Bytes(), err
				}
			}
		}
	}
	dot.WriteString("}")
	return dot.Bytes(), nil
}
RenderDot returns a representation of the dag in graphviz DOT file format.
Graphviz: http://graphviz.org/

DOT file format:
https://graphviz.gitlab.io/_pages/doc/info/lang.html

The DOT bytes could then be written to a file or piped to the graphviz `dot` command to generate a graphical
representation of the dag.
package blockdag
import (
	"bytes"
	"fmt"
	"github.com/soteria-dag/soterd/soterutil"
)