2024-01-25 11:04:09 +01:00
|
|
|
# fluffy
|
2024-01-13 08:41:57 +07:00
|
|
|
# Copyright (c) 2021-2024 Status Research & Development GmbH
|
2021-11-24 08:45:55 +01:00
|
|
|
# Licensed and distributed under either of
|
|
|
|
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
|
|
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2023-01-31 13:38:08 +01:00
|
|
|
{.push raises: [].}
|
2021-11-24 08:45:55 +01:00
|
|
|
|
|
|
|
import
|
2024-01-13 08:41:57 +07:00
|
|
|
std/[sequtils, json],
|
2024-09-18 15:46:50 +08:00
|
|
|
json_rpc/rpcserver,
|
2024-01-13 08:41:57 +07:00
|
|
|
json_serialization/std/tables,
|
|
|
|
stew/byteutils,
|
2021-11-24 08:45:55 +01:00
|
|
|
../network/wire/portal_protocol,
|
|
|
|
./rpc_types
|
|
|
|
|
2024-03-06 08:57:09 +01:00
|
|
|
{.warning[UnusedImport]: off.}
|
|
|
|
import json_rpc/errors
|
|
|
|
|
2024-10-08 03:15:29 +02:00
|
|
|
export tables
|
2021-11-24 14:53:01 +01:00
|
|
|
|
2024-10-08 03:15:29 +02:00
|
|
|
# Portal Network JSON-RPC implementation as per specification:
|
2023-01-17 14:47:10 +01:00
|
|
|
# https://github.com/ethereum/portal-network-specs/tree/master/jsonrpc
|
|
|
|
|
2024-01-13 08:41:57 +07:00
|
|
|
ContentInfo.useDefaultSerializationIn JrpcConv
|
|
|
|
TraceContentLookupResult.useDefaultSerializationIn JrpcConv
|
|
|
|
TraceObject.useDefaultSerializationIn JrpcConv
|
|
|
|
NodeMetadata.useDefaultSerializationIn JrpcConv
|
|
|
|
TraceResponse.useDefaultSerializationIn JrpcConv
|
2023-10-30 17:48:06 +03:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
proc installPortalBeaconApiHandlers*(rpcServer: RpcServer, p: PortalProtocol) =
|
|
|
|
rpcServer.rpc("portal_beaconFindContent") do(
|
2024-02-28 18:31:45 +01:00
|
|
|
enr: Record, contentKey: string
|
|
|
|
) -> JsonString:
|
2022-01-14 16:07:14 +01:00
|
|
|
let
|
|
|
|
node = toNodeWithAddress(enr)
|
2024-02-28 18:31:45 +01:00
|
|
|
foundContentResult =
|
2024-07-17 17:07:27 +02:00
|
|
|
await p.findContent(node, ContentKeyByteList.init(hexToSeqByte(contentKey)))
|
2022-01-14 16:07:14 +01:00
|
|
|
|
|
|
|
if foundContentResult.isErr():
|
|
|
|
raise newException(ValueError, $foundContentResult.error)
|
|
|
|
else:
|
|
|
|
let foundContent = foundContentResult.get()
|
2024-02-28 18:31:45 +01:00
|
|
|
case foundContent.kind
|
2022-01-14 16:07:14 +01:00
|
|
|
of Content:
|
2024-01-13 08:41:57 +07:00
|
|
|
let res = ContentInfo(
|
2024-02-28 18:31:45 +01:00
|
|
|
content: foundContent.content.to0xHex(), utpTransfer: foundContent.utpTransfer
|
2023-04-28 09:04:21 +02:00
|
|
|
)
|
2024-01-13 08:41:57 +07:00
|
|
|
return JrpcConv.encode(res).JsonString
|
2022-01-14 16:07:14 +01:00
|
|
|
of Nodes:
|
2024-02-28 18:31:45 +01:00
|
|
|
let enrs = foundContent.nodes.map(
|
|
|
|
proc(n: Node): Record =
|
|
|
|
n.record
|
|
|
|
)
|
2024-01-13 08:41:57 +07:00
|
|
|
let jsonEnrs = JrpcConv.encode(enrs)
|
|
|
|
return ("{\"enrs\":" & jsonEnrs & "}").JsonString
|
2022-01-14 16:07:14 +01:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
rpcServer.rpc("portal_beaconOffer") do(
|
2024-10-07 10:49:04 +02:00
|
|
|
enr: Record, contentItems: seq[ContentItem]
|
2024-02-28 18:31:45 +01:00
|
|
|
) -> string:
|
2024-10-07 10:49:04 +02:00
|
|
|
let node = toNodeWithAddress(enr)
|
2022-12-16 17:47:52 +01:00
|
|
|
|
2024-10-07 10:49:04 +02:00
|
|
|
var contentItemsToOffer: seq[ContentKV]
|
|
|
|
for contentItem in contentItems:
|
|
|
|
let
|
|
|
|
contentKey = hexToSeqByte(contentItem[0])
|
|
|
|
contentValue = hexToSeqByte(contentItem[1])
|
|
|
|
contentKV = ContentKV(
|
|
|
|
contentKey: ContentKeyByteList.init(contentKey), content: contentValue
|
|
|
|
)
|
|
|
|
contentItemsToOffer.add(contentKV)
|
|
|
|
|
|
|
|
let offerResult = (await p.offer(node, contentItemsToOffer)).valueOr:
|
|
|
|
raise newException(ValueError, $error)
|
|
|
|
|
|
|
|
SSZ.encode(offerResult).to0xHex()
|
2022-12-16 17:47:52 +01:00
|
|
|
|
2024-10-14 16:46:35 +08:00
|
|
|
rpcServer.rpc("portal_beaconGetContent") do(contentKey: string) -> ContentInfo:
|
2022-12-16 08:49:18 +01:00
|
|
|
let
|
2024-07-17 17:07:27 +02:00
|
|
|
key = ContentKeyByteList.init(hexToSeqByte(contentKey))
|
2022-12-16 08:49:18 +01:00
|
|
|
contentId = p.toContentId(key).valueOr:
|
2024-10-08 15:21:27 +08:00
|
|
|
raise invalidKeyErr()
|
2022-12-16 08:49:18 +01:00
|
|
|
|
|
|
|
contentResult = (await p.contentLookup(key, contentId)).valueOr:
|
2024-10-08 15:21:27 +08:00
|
|
|
raise contentNotFoundErr()
|
2022-12-16 08:49:18 +01:00
|
|
|
|
2023-08-24 18:19:29 +02:00
|
|
|
return ContentInfo(
|
2024-02-28 18:31:45 +01:00
|
|
|
content: contentResult.content.to0xHex(), utpTransfer: contentResult.utpTransfer
|
|
|
|
)
|
2022-12-16 08:49:18 +01:00
|
|
|
|
2024-10-14 16:46:35 +08:00
|
|
|
rpcServer.rpc("portal_beaconTraceGetContent") do(
|
2024-02-28 18:31:45 +01:00
|
|
|
contentKey: string
|
|
|
|
) -> TraceContentLookupResult:
|
2023-10-30 17:48:06 +03:00
|
|
|
let
|
2024-07-17 17:07:27 +02:00
|
|
|
key = ContentKeyByteList.init(hexToSeqByte(contentKey))
|
2023-10-30 17:48:06 +03:00
|
|
|
contentId = p.toContentId(key).valueOr:
|
2024-10-08 15:21:27 +08:00
|
|
|
raise invalidKeyErr()
|
2024-03-06 08:57:09 +01:00
|
|
|
|
|
|
|
res = await p.traceContentLookup(key, contentId)
|
2023-10-30 17:48:06 +03:00
|
|
|
|
2024-03-06 08:57:09 +01:00
|
|
|
# TODO: Might want to restructure the lookup result here. Potentially doing
|
|
|
|
# the json conversion in this module.
|
|
|
|
if res.content.isSome():
|
|
|
|
return res
|
|
|
|
else:
|
|
|
|
let data = Opt.some(JrpcConv.encode(res.trace).JsonString)
|
2024-10-08 15:21:27 +08:00
|
|
|
raise contentNotFoundErrWithTrace(data)
|
2023-10-30 17:48:06 +03:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
rpcServer.rpc("portal_beaconStore") do(
|
2024-02-28 18:31:45 +01:00
|
|
|
contentKey: string, contentValue: string
|
|
|
|
) -> bool:
|
2024-06-11 21:01:35 +08:00
|
|
|
let
|
2024-07-17 17:07:27 +02:00
|
|
|
key = ContentKeyByteList.init(hexToSeqByte(contentKey))
|
2024-06-11 21:01:35 +08:00
|
|
|
contentValueBytes = hexToSeqByte(contentValue)
|
2024-10-09 20:23:46 +08:00
|
|
|
contentId = p.toContentId(key).valueOr:
|
|
|
|
raise invalidKeyErr()
|
2024-06-11 21:01:35 +08:00
|
|
|
|
2024-10-09 20:23:46 +08:00
|
|
|
p.storeContent(key, contentId, contentValueBytes)
|
2022-12-16 11:00:10 +01:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
rpcServer.rpc("portal_beaconLocalContent") do(contentKey: string) -> string:
|
2022-12-16 11:00:10 +01:00
|
|
|
let
|
2024-07-17 17:07:27 +02:00
|
|
|
key = ContentKeyByteList.init(hexToSeqByte(contentKey))
|
2022-12-16 11:00:10 +01:00
|
|
|
contentId = p.toContentId(key).valueOr:
|
2024-10-08 15:21:27 +08:00
|
|
|
raise invalidKeyErr()
|
2022-12-16 11:00:10 +01:00
|
|
|
|
2023-04-27 14:07:57 +02:00
|
|
|
contentResult = p.dbGet(key, contentId).valueOr:
|
2024-10-08 15:21:27 +08:00
|
|
|
raise contentNotFoundErr()
|
2023-04-27 14:07:57 +02:00
|
|
|
|
|
|
|
return contentResult.to0xHex()
|
2023-01-17 14:47:10 +01:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
rpcServer.rpc("portal_beaconGossip") do(
|
2024-02-28 18:31:45 +01:00
|
|
|
contentKey: string, contentValue: string
|
|
|
|
) -> int:
|
2023-01-17 14:47:10 +01:00
|
|
|
let
|
|
|
|
key = hexToSeqByte(contentKey)
|
|
|
|
content = hexToSeqByte(contentValue)
|
2024-07-17 17:07:27 +02:00
|
|
|
contentKeys = ContentKeysList(@[ContentKeyByteList.init(key)])
|
2024-02-28 18:31:45 +01:00
|
|
|
numberOfPeers =
|
|
|
|
await p.neighborhoodGossip(Opt.none(NodeId), contentKeys, @[content])
|
2023-01-17 14:47:10 +01:00
|
|
|
|
|
|
|
return numberOfPeers
|
2023-10-05 19:29:39 +02:00
|
|
|
|
2024-10-07 22:33:02 +08:00
|
|
|
rpcServer.rpc("portal_beaconRandomGossip") do(
|
2024-02-28 18:31:45 +01:00
|
|
|
contentKey: string, contentValue: string
|
|
|
|
) -> int:
|
2023-10-05 19:29:39 +02:00
|
|
|
let
|
|
|
|
key = hexToSeqByte(contentKey)
|
|
|
|
content = hexToSeqByte(contentValue)
|
2024-07-17 17:07:27 +02:00
|
|
|
contentKeys = ContentKeysList(@[ContentKeyByteList.init(key)])
|
2023-10-05 19:29:39 +02:00
|
|
|
numberOfPeers = await p.randomGossip(Opt.none(NodeId), contentKeys, @[content])
|
|
|
|
|
|
|
|
return numberOfPeers
|