@@ -14,6 +14,7 @@ import (
1414 "math/rand"
1515 "net"
1616 "sort"
17+ "sync"
1718 "time"
1819
1920 "github.com/ethereum/go-ethereum/common/hexutil"
@@ -124,6 +125,13 @@ type ContentInfoRes struct {
124125 UtpTransfer bool
125126}
126127
128+ type traceContentInfoRes struct {
129+ Node * enode.Node
130+ Flag byte
131+ Content any
132+ UtpTransfer bool
133+ }
134+
127135type PortalProtocolOption func (p * PortalProtocol )
128136
129137type PortalProtocolConfig struct {
@@ -1499,7 +1507,124 @@ func (p *PortalProtocol) contentLookupWorker(n *enode.Node, contentKey []byte, r
14991507 return wrapedNode , nil
15001508}
15011509
1502- // func (p *PortalProtocol) traceContentLookupWorker()
1510+ func (p * PortalProtocol ) TraceContentLookup (contentKey []byte ) (* TraceContentResult , error ) {
1511+ lookupContext , cancel := context .WithCancel (context .Background ())
1512+ defer cancel ()
1513+ requestNodeChan := make (chan * enode.Node , 3 )
1514+ resChan := make (chan * traceContentInfoRes , 3 )
1515+
1516+ requestNode := make ([]* enode.Node , 0 )
1517+ requestRes := make (map [string ]* traceContentInfoRes )
1518+
1519+ traceContentRes := & TraceContentResult {}
1520+
1521+ trace := & Trace {
1522+ Origin : p .Self ().ID ().String (),
1523+ TargetId : hexutil .Encode (p .ToContentId (contentKey )),
1524+ StartedAtMs : int (time .Now ().UnixMilli ()),
1525+ Responses : make (map [string ][]string ),
1526+ Metadata : make (map [string ]* NodeMetadata ),
1527+ Cancelled : make ([]string , 0 ),
1528+ }
1529+
1530+ var wg sync.WaitGroup
1531+ wg .Add (2 )
1532+ go func () {
1533+ defer wg .Done ()
1534+ for node := range requestNodeChan {
1535+ requestNode = append (requestNode , node )
1536+ }
1537+ }()
1538+
1539+ go func () {
1540+ defer wg .Done ()
1541+ for res := range resChan {
1542+ key := res .Node .ID ().String ()
1543+ requestRes [key ] = res
1544+ if res .Flag == portalwire .ContentRawSelector || res .Flag == portalwire .ContentConnIdSelector {
1545+ // get the content
1546+ return
1547+ }
1548+ }
1549+ }()
1550+
1551+ newLookup (lookupContext , p .table , p .Self ().ID (), func (n * node ) ([]* node , error ) {
1552+ node := unwrapNode (n )
1553+ requestNodeChan <- node
1554+ return p .traceContentLookupWorker (node , contentKey , resChan )
1555+ }).run ()
1556+
1557+ close (requestNodeChan )
1558+ close (resChan )
1559+
1560+ wg .Wait ()
1561+
1562+ for _ , node := range requestNode {
1563+ id := node .ID ().String ()
1564+ trace .Metadata [id ] = & NodeMetadata {
1565+ Enr : node .String (),
1566+ //Distance: node.Seq(),
1567+ }
1568+ if res , ok := requestRes [id ]; ok {
1569+ if res .Flag == portalwire .ContentRawSelector || res .Flag == portalwire .ContentConnIdSelector {
1570+ trace .ReceivedFrom = res .Node .ID ().String ()
1571+ content := res .Content .([]byte )
1572+ traceContentRes .Content = hexutil .Encode (content )
1573+ traceContentRes .UtpTransfer = res .UtpTransfer
1574+ } else {
1575+ content := res .Content .([]* enode.Node )
1576+ ids := make ([]string , 0 )
1577+ for _ , n := range content {
1578+ ids = append (ids , n .ID ().String ())
1579+ }
1580+ trace .Responses [id ] = ids
1581+ }
1582+ } else {
1583+ trace .Cancelled = append (trace .Cancelled , id )
1584+ }
1585+ }
1586+
1587+ traceContentRes .Trace = * trace
1588+
1589+ return traceContentRes , nil
1590+ }
1591+
1592+ func (p * PortalProtocol ) traceContentLookupWorker (n * enode.Node , contentKey []byte , resChan chan <- * traceContentInfoRes ) ([]* node , error ) {
1593+ wrapedNode := make ([]* node , 0 )
1594+ flag , content , err := p .findContent (n , contentKey )
1595+ if err != nil {
1596+ return nil , err
1597+ }
1598+ switch flag {
1599+ case portalwire .ContentRawSelector , portalwire .ContentConnIdSelector :
1600+ content , ok := content .([]byte )
1601+ if ! ok {
1602+ return wrapedNode , fmt .Errorf ("failed to assert to raw content, value is: %v" , content )
1603+ }
1604+ res := & traceContentInfoRes {
1605+ Node : n ,
1606+ Flag : flag ,
1607+ Content : content ,
1608+ UtpTransfer : false ,
1609+ }
1610+ if flag == portalwire .ContentConnIdSelector {
1611+ res .UtpTransfer = true
1612+ }
1613+ resChan <- res
1614+ return wrapedNode , err
1615+ case portalwire .ContentEnrsSelector :
1616+ nodes , ok := content .([]* enode.Node )
1617+ if ! ok {
1618+ return wrapedNode , fmt .Errorf ("failed to assert to enrs content, value is: %v" , content )
1619+ }
1620+ resChan <- & traceContentInfoRes {Node : n ,
1621+ Flag : flag ,
1622+ Content : content ,
1623+ UtpTransfer : false }
1624+ return wrapNodes (nodes ), nil
1625+ }
1626+ return wrapedNode , nil
1627+ }
15031628
15041629func (p * PortalProtocol ) ToContentId (contentKey []byte ) []byte {
15051630 return p .toContentId (contentKey )
0 commit comments