Validate content in portal protocol.
This commit is contained in:
parent
ab475cccdc
commit
e881144557
|
@ -90,32 +90,39 @@ proc getContent(
|
|||
info "Fetched state local content value"
|
||||
return Opt.some(contentValue)
|
||||
|
||||
for i in 0 ..< (1 + n.contentRequestRetries):
|
||||
let
|
||||
contentLookupResult = (
|
||||
await n.portalProtocol.contentLookup(contentKeyBytes, contentId)
|
||||
).valueOr:
|
||||
warn "Failed fetching state content from the network"
|
||||
return Opt.none(V)
|
||||
contentValueBytes = contentLookupResult.content
|
||||
|
||||
let contentValue = V.decode(contentValueBytes).valueOr:
|
||||
# Define the state content validation closure
|
||||
proc stateContentValidator(
|
||||
contentKey: ContentKeyByteList, content: seq[byte]
|
||||
): bool {.raises: [], gcsafe.} =
|
||||
let contentValue = V.decode(content).valueOr:
|
||||
warn "Unable to decode state content value from content lookup"
|
||||
continue
|
||||
return false
|
||||
|
||||
validateRetrieval(key, contentValue).isOkOr:
|
||||
if validateRetrieval(key, contentValue).isOk():
|
||||
true
|
||||
else:
|
||||
warn "Validation of retrieved state content failed"
|
||||
continue
|
||||
false
|
||||
|
||||
info "Fetched valid state content from the network"
|
||||
n.portalProtocol.storeContent(
|
||||
contentKeyBytes, contentId, contentValueBytes, cacheContent = true
|
||||
)
|
||||
let
|
||||
contentLookupResult = (
|
||||
await n.portalProtocol.contentLookup(
|
||||
contentKeyBytes, contentId, stateContentValidator
|
||||
)
|
||||
).valueOr:
|
||||
warn "Failed fetching state content from the network"
|
||||
return Opt.none(V)
|
||||
contentValueBytes = contentLookupResult.content
|
||||
|
||||
return Opt.some(contentValue)
|
||||
info "Fetched valid state content from the network"
|
||||
n.portalProtocol.storeContent(
|
||||
contentKeyBytes, contentId, contentValueBytes, cacheContent = true
|
||||
)
|
||||
|
||||
# Content was requested `1 + requestRetries` times and all failed on validation
|
||||
Opt.none(V)
|
||||
let contentValue = V.decode(contentValueBytes).valueOr:
|
||||
raiseAssert("Content should already have been validated")
|
||||
|
||||
return Opt.some(contentValue)
|
||||
|
||||
proc getAccountTrieNode*(
|
||||
n: StateNetwork, key: AccountTrieNodeKey
|
||||
|
|
|
@ -153,16 +153,20 @@ type
|
|||
|
||||
DbRadiusHandler* = proc(): UInt256 {.raises: [], gcsafe.}
|
||||
|
||||
ContentValidationHandler* = proc(
|
||||
contentKey: ContentKeyByteList, content: seq[byte]
|
||||
): bool {.raises: [], gcsafe.}
|
||||
|
||||
PortalProtocolId* = array[2, byte]
|
||||
|
||||
RadiusCache* = LRUCache[NodeId, UInt256]
|
||||
|
||||
ContentCache = LRUCache[ContentId, seq[byte]]
|
||||
|
||||
ContentKV* = object
|
||||
contentKey*: ContentKeyByteList
|
||||
content*: seq[byte]
|
||||
|
||||
ContentCache = LRUCache[ContentId, seq[byte]]
|
||||
|
||||
OfferRequestType = enum
|
||||
Direct
|
||||
Database
|
||||
|
@ -1125,11 +1129,19 @@ proc triggerPoke*(
|
|||
# Offer queue is full, do not start more offer-accept interactions
|
||||
return
|
||||
|
||||
proc defaultContentValidator(
|
||||
contentKey: ContentKeyByteList, content: seq[byte]
|
||||
): bool {.raises: [], gcsafe.} =
|
||||
true
|
||||
|
||||
# TODO ContentLookup and Lookup look almost exactly the same, also lookups in other
|
||||
# networks will probably be very similar. Extract lookup function to separate module
|
||||
# and make it more generaic
|
||||
proc contentLookup*(
|
||||
p: PortalProtocol, target: ContentKeyByteList, targetId: UInt256
|
||||
p: PortalProtocol,
|
||||
target: ContentKeyByteList,
|
||||
targetId: UInt256,
|
||||
validationHandler: ContentValidationHandler = defaultContentValidator,
|
||||
): Future[Opt[ContentLookupResult]] {.async: (raises: [CancelledError]).} =
|
||||
## Perform a lookup for the given target, return the closest n nodes to the
|
||||
## target. Maximum value for n is `BUCKET_SIZE`.
|
||||
|
@ -1212,17 +1224,21 @@ proc contentLookup*(
|
|||
if closestNodes.len > BUCKET_SIZE:
|
||||
closestNodes.del(closestNodes.high())
|
||||
of Content:
|
||||
# cancel any pending queries as the content has been found
|
||||
for f in pendingQueries:
|
||||
f.cancelSoon()
|
||||
portal_lookup_content_requests.observe(
|
||||
requestAmount, labelValues = [$p.protocolId]
|
||||
)
|
||||
return Opt.some(
|
||||
ContentLookupResult.init(
|
||||
content.content, content.utpTransfer, nodesWithoutContent
|
||||
if validationHandler(target, content.content):
|
||||
# cancel any pending queries as the content has been found
|
||||
for f in pendingQueries:
|
||||
f.cancelSoon()
|
||||
portal_lookup_content_requests.observe(
|
||||
requestAmount, labelValues = [$p.protocolId]
|
||||
)
|
||||
)
|
||||
return Opt.some(
|
||||
ContentLookupResult.init(
|
||||
content.content, content.utpTransfer, nodesWithoutContent
|
||||
)
|
||||
)
|
||||
else:
|
||||
# TODO: What should we do if the validation fails?
|
||||
discard
|
||||
else:
|
||||
# TODO: Should we do something with the node that failed responding our
|
||||
# query?
|
||||
|
|
Loading…
Reference in New Issue