diff --git a/p2p/discover/api.go b/p2p/discover/api.go index 9b58b2d7ec27..27c0a67ccdd2 100644 --- a/p2p/discover/api.go +++ b/p2p/discover/api.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/p2p/discover/portalwire" "github.com/ethereum/go-ethereum/p2p/enode" + "github.com/ethereum/go-ethereum/portalnetwork/storage" "github.com/holiman/uint256" ) @@ -432,3 +433,55 @@ func (p *PortalAPI) HistoryRecursiveFindNodes(nodeId string) ([]string, error) { return enrs, nil } + +func (p *PortalAPI) HistoryRecursiveFindContent(contentKeyHex string) (*ContentInfo, error) { + contentKey, err := hexutil.Decode(contentKeyHex) + if err != nil { + return nil, err + } + content, utpTransfer, err := p.portalProtocol.ContentLookup(contentKey) + if err != nil { + return nil, err + } + + return &ContentInfo{ + Content: hexutil.Encode(content), + UtpTransfer: utpTransfer, + }, err +} + +func (p *PortalAPI) HistoryLocalContent(contentKeyHex string) (string, error) { + contentKey, err := hexutil.Decode(contentKeyHex) + if err != nil { + return "", err + } + contentId := p.portalProtocol.ToContentId(contentKey) + content, err := p.portalProtocol.Get(contentId) + if errors.Is(err, storage.ErrContentNotFound) { + return "0x", nil + } + if err != nil { + return "", err + } + return hexutil.Encode(content), nil +} + +func (p *PortalAPI) HistoryStore(contentKeyHex string, contextHex string) (bool, error) { + contentKey, err := hexutil.Decode(contentKeyHex) + if err != nil { + return false, err + } + contentId := p.portalProtocol.ToContentId(contentKey) + if !p.portalProtocol.InRange(contentId) { + return false, nil + } + content, err := hexutil.Decode(contextHex) + if err != nil { + return false, err + } + err = p.portalProtocol.Put(contentId, content) + if err != nil { + return false, err + } + return true, nil +} diff --git a/p2p/discover/portal_protocol.go b/p2p/discover/portal_protocol.go index 0b37669fcd1a..0d0f95697dcc 100644 --- a/p2p/discover/portal_protocol.go +++ b/p2p/discover/portal_protocol.go @@ -112,6 +112,11 @@ type OfferRequestWithNode struct { Node *enode.Node } +type ContentInfoRes struct { + Content []byte + UtpTransfer bool +} + type PortalProtocolOption func(p *PortalProtocol) type PortalProtocolConfig struct { @@ -1402,22 +1407,23 @@ func (p *PortalProtocol) collectTableNodes(rip net.IP, distances []uint, limit i return nodes } -func (p *PortalProtocol) ContentLookup(contentKey []byte) ([]byte, error) { +func (p *PortalProtocol) ContentLookup(contentKey []byte) ([]byte, bool, error) { lookupContext, cancel := context.WithCancel(context.Background()) defer cancel() - resChan := make(chan []byte, 1) + resChan := make(chan *ContentInfoRes, 1) defer close(resChan) newLookup(lookupContext, p.table, p.Self().ID(), func(n *node) ([]*node, error) { return p.contentLookupWorker(unwrapNode(n), contentKey, resChan) }).run() if len(resChan) > 0 { - return <-resChan, nil + res := <-resChan + return res.Content, res.UtpTransfer, nil } - return nil, ContentNotFound + return nil, false, ContentNotFound } -func (p *PortalProtocol) contentLookupWorker(n *enode.Node, contentKey []byte, resChan chan<- []byte) ([]*node, error) { +func (p *PortalProtocol) contentLookupWorker(n *enode.Node, contentKey []byte, resChan chan<- *ContentInfoRes) ([]*node, error) { wrapedNode := make([]*node, 0) flag, content, err := p.findContent(n, contentKey) if err != nil { @@ -1429,7 +1435,13 @@ func (p *PortalProtocol) contentLookupWorker(n *enode.Node, contentKey []byte, r if !ok { return wrapedNode, fmt.Errorf("failed to assert to raw content, value is: %v", content) } - resChan <- content + res := &ContentInfoRes{ + Content: content, + } + if flag == portalwire.ContentConnIdSelector { + res.UtpTransfer = true + } + resChan <- res return wrapedNode, err case portalwire.ContentEnrsSelector: nodes, ok := content.([]*enode.Node) diff --git a/p2p/discover/portal_protocol_test.go b/p2p/discover/portal_protocol_test.go index 270d4290ffc5..07af0009dd23 100644 --- a/p2p/discover/portal_protocol_test.go +++ b/p2p/discover/portal_protocol_test.go @@ -392,11 +392,11 @@ func TestContentLookup(t *testing.T) { err = node3.storage.Put(contentId, content) assert.NoError(t, err) - res, err := node1.ContentLookup(contentKey) + res, _, err := node1.ContentLookup(contentKey) assert.NoError(t, err) assert.Equal(t, res, content) - res, err = node1.ContentLookup([]byte{0x2, 0x4}) + res, _, err = node1.ContentLookup([]byte{0x2, 0x4}) assert.Equal(t, ContentNotFound, err) assert.Nil(t, res) } diff --git a/portalnetwork/history/history_network.go b/portalnetwork/history/history_network.go index 02e5626e5a66..e3d758f77d60 100644 --- a/portalnetwork/history/history_network.go +++ b/portalnetwork/history/history_network.go @@ -114,7 +114,7 @@ func (h *HistoryNetwork) GetBlockHeader(blockHash []byte) (*types.Header, error) // no content in local storage for retries := 0; retries < requestRetries; retries++ { // TODO log the err and continue - content, err := h.portalProtocol.ContentLookup(contentKey) + content, _, err := h.portalProtocol.ContentLookup(contentKey) if err != nil { continue } @@ -165,7 +165,7 @@ func (h *HistoryNetwork) GetBlockBody(blockHash []byte) (*types.Body, error) { // no content in local storage for retries := 0; retries < requestRetries; retries++ { - content, err := h.portalProtocol.ContentLookup(contentKey) + content, _, err := h.portalProtocol.ContentLookup(contentKey) if err != nil { continue } @@ -215,7 +215,7 @@ func (h *HistoryNetwork) GetReceipts(blockHash []byte) ([]*types.Receipt, error) // no content in local storage for retries := 0; retries < requestRetries; retries++ { - content, err := h.portalProtocol.ContentLookup(contentKey) + content, _, err := h.portalProtocol.ContentLookup(contentKey) if err != nil { continue } @@ -245,7 +245,7 @@ func (h *HistoryNetwork) GetEpochAccumulator(epochHash []byte) (*EpochAccumulato return epochAccu, err } for retries := 0; retries < requestRetries; retries++ { - content, err := h.portalProtocol.ContentLookup(contentKey) + content, _, err := h.portalProtocol.ContentLookup(contentKey) if err != nil { continue }