Skip to content

Commit 7c84a27

Browse files
feat: helper functions for label recalculation and tests to ensure they are deterministic
1 parent 1d6c07c commit 7c84a27

3 files changed

Lines changed: 515 additions & 0 deletions

File tree

dag/dag.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,3 +1500,141 @@ func (packet *BatchedTransmissionPacket) GetRootLeaf() *DagLeaf {
15001500

15011501
return packet.Leaves[0]
15021502
}
1503+
1504+
// RecomputeLabels reassigns all labels in the DAG in optimal traversal order.
1505+
func (d *Dag) RecomputeLabels() error {
1506+
if d.Root == "" {
1507+
return fmt.Errorf("cannot recompute labels: DAG has no root")
1508+
}
1509+
1510+
if _, exists := d.Leafs[d.Root]; !exists {
1511+
return fmt.Errorf("cannot recompute labels: root leaf not found")
1512+
}
1513+
1514+
// Track bare hash -> new label mapping
1515+
labelMapping := make(map[string]string)
1516+
1517+
// The root never gets a label
1518+
rootBareHash := StripLabel(d.Root)
1519+
labelMapping[rootBareHash] = "" // Empty label for root
1520+
1521+
// Breadth-first traversal
1522+
currentLabel := 1
1523+
queue := []string{rootBareHash}
1524+
visited := make(map[string]bool)
1525+
visited[rootBareHash] = true
1526+
1527+
for len(queue) > 0 {
1528+
currentBareHash := queue[0]
1529+
queue = queue[1:]
1530+
1531+
// Find the leaf with this bare hash
1532+
var currentLeaf *DagLeaf
1533+
for hash, leaf := range d.Leafs {
1534+
if StripLabel(hash) == currentBareHash {
1535+
currentLeaf = leaf
1536+
break
1537+
}
1538+
}
1539+
1540+
if currentLeaf == nil {
1541+
continue
1542+
}
1543+
1544+
// Process all children of this leaf
1545+
childHashes := make([]string, 0, len(currentLeaf.Links))
1546+
for _, childHashWithLabel := range currentLeaf.Links {
1547+
childBareHash := StripLabel(childHashWithLabel)
1548+
childHashes = append(childHashes, childBareHash)
1549+
}
1550+
sort.Strings(childHashes)
1551+
1552+
for _, childBareHash := range childHashes {
1553+
1554+
// Skip if already visited
1555+
if visited[childBareHash] {
1556+
continue
1557+
}
1558+
visited[childBareHash] = true
1559+
1560+
// Assign new label
1561+
newLabel := strconv.Itoa(currentLabel)
1562+
currentLabel++
1563+
1564+
labelMapping[childBareHash] = newLabel
1565+
1566+
// Add to queue for processing
1567+
queue = append(queue, childBareHash)
1568+
}
1569+
}
1570+
1571+
newLeafs := make(map[string]*DagLeaf)
1572+
1573+
for oldHash, leaf := range d.Leafs {
1574+
bareHash := StripLabel(oldHash)
1575+
1576+
// Get the new label for this leaf
1577+
newLabel, exists := labelMapping[bareHash]
1578+
if !exists {
1579+
// This leaf wasn't visited (shouldn't happen in a valid DAG)
1580+
continue
1581+
}
1582+
1583+
// Construct new hash
1584+
var newHash string
1585+
if newLabel == "" {
1586+
// Root leaf - no label
1587+
newHash = bareHash
1588+
} else {
1589+
newHash = newLabel + ":" + bareHash
1590+
}
1591+
1592+
// Update the leaf's Hash field
1593+
leaf.Hash = newHash
1594+
1595+
// Update all the links to children with new labels
1596+
if len(leaf.Links) > 0 {
1597+
newLinks := make(map[string]string)
1598+
for _, childHashWithOldLabel := range leaf.Links {
1599+
childBareHash := StripLabel(childHashWithOldLabel)
1600+
1601+
// Get the new label for this child
1602+
childNewLabel, exists := labelMapping[childBareHash]
1603+
if !exists {
1604+
// Child wasn't visited (shouldn't happen)
1605+
continue
1606+
}
1607+
1608+
// Construct new child hash
1609+
var newChildHash string
1610+
if childNewLabel == "" {
1611+
// Root as child (shouldn't happen normally)
1612+
newChildHash = childBareHash
1613+
} else {
1614+
newChildHash = childNewLabel + ":" + childBareHash
1615+
}
1616+
1617+
// Add link with new label as key
1618+
newLinks[childNewLabel] = newChildHash
1619+
}
1620+
leaf.Links = newLinks
1621+
}
1622+
1623+
// Add to new leafs map with new hash as key
1624+
newLeafs[newHash] = leaf
1625+
}
1626+
1627+
// Replace the leafs map
1628+
d.Leafs = newLeafs
1629+
1630+
// Update root reference if needed
1631+
rootBare := StripLabel(d.Root)
1632+
d.Root = rootBare
1633+
1634+
// Update LatestLabel on root
1635+
if rootLeaf, exists := d.Leafs[d.Root]; exists {
1636+
rootLeaf.LatestLabel = strconv.Itoa(currentLabel - 1)
1637+
}
1638+
1639+
return nil
1640+
}

0 commit comments

Comments
 (0)