add reputation to REST API endpoints

This commit is contained in:
Sergei Tikhomirov 2025-08-07 17:40:40 +02:00
parent 23dd47dfbe
commit 1abe4f26e4
3 changed files with 62 additions and 13 deletions

View File

@ -35,9 +35,12 @@ proc setReputation*(
manager.reputationOf[peer] = repValue
proc getReputation*(manager: ReputationManager, peer: PeerId): Option[bool] =
if peer in manager.reputationOf:
result = manager.reputationOf[peer]
else:
try:
if peer in manager.reputationOf:
result = manager.reputationOf[peer]
else:
result = none(bool)
except KeyError:
result = none(bool)
### Lightpush-specific functionality ###
@ -66,3 +69,17 @@ proc updateReputationFromResponse*(
of NeutralResponse:
debug "Neutral response - reputation unchanged for peer", peer = peer
# Don't change reputation for neutral responses
### Reputation conversion utilities ###
proc convertReputationToString*(reputation: Option[bool]): Option[string] =
## Converts reputation from Option[bool] to Option[string]
## some(true) -> some("Good")
## some(false) -> some("Bad")
## none(bool) -> some("Neutral")
if reputation.isNone():
return some("Neutral")
elif reputation.get():
return some("Good")
else:
return some("Bad")

View File

@ -21,6 +21,7 @@ import
waku_node,
node/peer_manager,
waku_enr/sharding,
incentivization/reputation_manager,
],
../responses,
../serdes,
@ -60,20 +61,26 @@ type PeerProtocolTuple =
connected: Connectedness,
agent: string,
origin: PeerOrigin,
reputation: Option[bool],
]
proc tuplesToWakuPeers(peers: var WakuPeers, peersTup: seq[PeerProtocolTuple]) =
for peer in peersTup:
peers.add(
peer.multiaddr, peer.protocol, peer.shards, peer.connected, peer.agent,
peer.origin,
peer.origin, convertReputationToString(peer.reputation),
)
proc populateAdminPeerInfo(
peers: var WakuPeers, node: WakuNode, codec: Option[string] = none[string]()
) =
let pm = node.peerManager
if codec.isNone():
peers = node.peerManager.switch.peerStore.peers().mapIt(WakuPeer.init(it))
peers = node.peerManager.switch.peerStore.peers().mapIt(
WakuPeer.init(it, if pm.reputationManager.isSome(): pm.reputationManager.get().getReputation(it.peerId) else: none(bool))
)
else:
let peersTuples = node.peerManager.switch.peerStore.peers(codec.get()).mapIt(
(
@ -83,6 +90,7 @@ proc populateAdminPeerInfo(
connected: it.connectedness,
agent: it.agent,
origin: it.origin,
reputation: if pm.reputationManager.isSome(): pm.reputationManager.get().getReputation(it.peerId) else: none(bool),
)
)
tuplesToWakuPeers(peers, peersTuples)
@ -112,7 +120,9 @@ proc getRelayPeers(node: WakuNode): PeersOfShards =
relayPeers.add(
PeersOfShard(
shard: relayShard.shardId,
peers: toSeq(pubsubPeers).mapIt(WakuPeer.init(it, node.peerManager)),
peers: toSeq(pubsubPeers).mapIt(
WakuPeer.init(it, node.peerManager, if node.peerManager.reputationManager.isSome(): node.peerManager.reputationManager.get().getReputation(it.peerId) else: none(bool))
),
)
)
return relayPeers
@ -129,7 +139,9 @@ proc getMeshPeers(node: WakuNode): PeersOfShards =
meshPeers.add(
PeersOfShard(
shard: relayShard.shardId,
peers: toSeq(peers).mapIt(WakuPeer.init(it, node.peerManager)),
peers: toSeq(peers).mapIt(
WakuPeer.init(it, node.peerManager, if node.peerManager.reputationManager.isSome(): node.peerManager.reputationManager.get().getReputation(it.peerId) else: none(bool))
),
)
)
return meshPeers
@ -157,7 +169,8 @@ proc installAdminV1GetPeersHandler(router: var RestRouter, node: WakuNode) =
if node.peerManager.switch.peerStore.peerExists(peerIdVal):
let peerInfo = node.peerManager.switch.peerStore.getPeer(peerIdVal)
let peer = WakuPeer.init(peerInfo)
let reputation = if node.peerManager.reputationManager.isSome(): node.peerManager.reputationManager.get().getReputation(peerIdVal) else: none(bool)
let peer = WakuPeer.init(peerInfo, reputation)
let resp = RestApiResponse.jsonResponse(peer, status = Http200).valueOr:
error "An error occurred while building the json response: ", error = error
return RestApiResponse.internalServerError(
@ -258,7 +271,9 @@ proc installAdminV1GetPeersHandler(router: var RestRouter, node: WakuNode) =
let pubsubPeers =
node.wakuRelay.getConnectedPubSubPeers(topic).get(initHashSet[PubSubPeer](0))
let relayPeer = PeersOfShard(
shard: shard, peers: toSeq(pubsubPeers).mapIt(WakuPeer.init(it, node.peerManager))
shard: shard, peers: toSeq(pubsubPeers).mapIt(
WakuPeer.init(it, node.peerManager, if node.peerManager.reputationManager.isSome(): node.peerManager.reputationManager.get().getReputation(it.peerId) else: none(bool))
)
)
let resp = RestApiResponse.jsonResponse(relayPeer, status = Http200).valueOr:
@ -307,7 +322,9 @@ proc installAdminV1GetPeersHandler(router: var RestRouter, node: WakuNode) =
let peers =
node.wakuRelay.getPubSubPeersInMesh(topic).get(initHashSet[PubSubPeer](0))
let relayPeer = PeersOfShard(
shard: shard, peers: toSeq(peers).mapIt(WakuPeer.init(it, node.peerManager))
shard: shard, peers: toSeq(peers).mapIt(
WakuPeer.init(it, node.peerManager, if node.peerManager.reputationManager.isSome(): node.peerManager.reputationManager.get().getReputation(it.peerId) else: none(bool))
)
)
let resp = RestApiResponse.jsonResponse(relayPeer, status = Http200).valueOr:

View File

@ -7,7 +7,7 @@ import
json_serialization/lexer,
results,
libp2p/protocols/pubsub/pubsubpeer
import waku/[waku_core, node/peer_manager], ../serdes
import waku/[waku_core, node/peer_manager, incentivization/reputation_manager], ../serdes
#### Types
type WakuPeer* = object
@ -18,6 +18,7 @@ type WakuPeer* = object
agent*: string
origin*: PeerOrigin
score*: Option[float64]
reputation*: Option[string] # "Good", "Bad", or "Neutral"
type WakuPeers* = seq[WakuPeer]
@ -50,6 +51,7 @@ proc writeValue*(
writer.writeField("agent", value.agent)
writer.writeField("origin", value.origin)
writer.writeField("score", value.score)
writer.writeField("reputation", value.reputation)
writer.endRecord()
proc writeValue*(
@ -104,6 +106,7 @@ proc readValue*(
agent: Option[string]
origin: Option[PeerOrigin]
score: Option[float64]
reputation: Option[string]
for fieldName in readObjectFields(reader):
case fieldName
@ -135,6 +138,10 @@ proc readValue*(
if score.isSome():
reader.raiseUnexpectedField("Multiple `score` fields found", "WakuPeer")
score = some(reader.readValue(float64))
of "reputation":
if reputation.isSome():
reader.raiseUnexpectedField("Multiple `reputation` fields found", "WakuPeer")
reputation = some(reader.readValue(string))
else:
unrecognizedFieldWarning(value)
@ -164,6 +171,7 @@ proc readValue*(
agent: agent.get(),
origin: origin.get(),
score: score,
reputation: reputation,
)
proc readValue*(
@ -276,7 +284,9 @@ proc readValue*(
func `==`*(a, b: WakuPeer): bool {.inline.} =
return a.multiaddr == b.multiaddr
proc init*(T: type WakuPeer, peerInfo: RemotePeerInfo): WakuPeer =
proc init*(T: type WakuPeer, peerInfo: RemotePeerInfo, reputation: Option[bool] = none(bool)): WakuPeer =
result = WakuPeer(
multiaddr: constructMultiaddrStr(peerInfo),
protocols: peerInfo.protocols,
@ -285,9 +295,10 @@ proc init*(T: type WakuPeer, peerInfo: RemotePeerInfo): WakuPeer =
agent: peerInfo.agent,
origin: peerInfo.origin,
score: none(float64),
reputation: convertReputationToString(reputation),
)
proc init*(T: type WakuPeer, pubsubPeer: PubSubPeer, pm: PeerManager): WakuPeer =
proc init*(T: type WakuPeer, pubsubPeer: PubSubPeer, pm: PeerManager, reputation: Option[bool] = none(bool)): WakuPeer =
let peerInfo = pm.getPeer(pubsubPeer.peerId)
result = WakuPeer(
multiaddr: constructMultiaddrStr(peerInfo),
@ -297,6 +308,7 @@ proc init*(T: type WakuPeer, pubsubPeer: PubSubPeer, pm: PeerManager): WakuPeer
agent: peerInfo.agent,
origin: peerInfo.origin,
score: some(pubsubPeer.score),
reputation: convertReputationToString(reputation),
)
proc add*(
@ -307,6 +319,7 @@ proc add*(
connected: Connectedness,
agent: string,
origin: PeerOrigin,
reputation: Option[string] = none(string),
) =
var peer: WakuPeer = WakuPeer(
multiaddr: multiaddr,
@ -315,6 +328,8 @@ proc add*(
connected: connected,
agent: agent,
origin: origin,
score: none(float64),
reputation: reputation,
)
let idx = peers.find(peer)