Skip to content

Commit

Permalink
feat: incentivization PoC: client-side reputation system basics (#3293)
Browse files Browse the repository at this point in the history
* chore: rename test file for eligibility tests

* add reputation manager

* add simple boolean reputation with dummy response

* set default reputation to true

* use reputation indicator term; remove unnecessary updateReputation

* use PushResponse in reputation manager

* add custom type for reputation

* add reputation update from response quality

* encode reputation indicators as Option[bool]
  • Loading branch information
s-tikhomirov authored Feb 20, 2025
1 parent a3876f1 commit a4e92a3
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 1 deletion.
2 changes: 1 addition & 1 deletion tests/incentivization/test_all.nim
Original file line number Diff line number Diff line change
@@ -1 +1 @@
import ./test_rpc_codec, ./test_poc
import ./test_rpc_codec, ./test_poc_eligibility, ./test_poc_reputation
File renamed without changes.
54 changes: 54 additions & 0 deletions tests/incentivization/test_poc_reputation.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import
std/options,
testutils/unittests,
chronos,
web3,
stew/byteutils,
stint,
strutils,
tests/testlib/testasync

import
waku/[node/peer_manager, waku_core],
waku/incentivization/[rpc, reputation_manager],
waku/waku_lightpush/rpc

suite "Waku Incentivization PoC Reputation":
var manager {.threadvar.}: ReputationManager

setup:
manager = ReputationManager.init()

test "incentivization PoC: reputation: reputation table is empty after initialization":
check manager.reputationOf.len == 0

test "incentivization PoC: reputation: set and get reputation":
manager.setReputation("peer1", some(true)) # Encodes GoodRep
check manager.getReputation("peer1") == some(true)

test "incentivization PoC: reputation: evaluate PushResponse valid":
let validLightpushResponse =
PushResponse(isSuccess: true, info: some("Everything is OK"))
# We expect evaluateResponse to return GoodResponse if isSuccess is true
check evaluateResponse(validLightpushResponse) == GoodResponse

test "incentivization PoC: reputation: evaluate PushResponse invalid":
let invalidLightpushResponse = PushResponse(isSuccess: false, info: none(string))
check evaluateResponse(invalidLightpushResponse) == BadResponse

test "incentivization PoC: reputation: updateReputationFromResponse valid":
let peerId = "peerWithValidResponse"
let validResp = PushResponse(isSuccess: true, info: some("All good"))
manager.updateReputationFromResponse(peerId, validResp)
check manager.getReputation(peerId) == some(true)

test "incentivization PoC: reputation: updateReputationFromResponse invalid":
let peerId = "peerWithInvalidResponse"
let invalidResp = PushResponse(isSuccess: false, info: none(string))
manager.updateReputationFromResponse(peerId, invalidResp)
check manager.getReputation(peerId) == some(false)

test "incentivization PoC: reputation: default is None":
let unknownPeerId = "unknown_peer"
# The peer is not in the table yet
check manager.getReputation(unknownPeerId) == none(bool)
48 changes: 48 additions & 0 deletions waku/incentivization/reputation_manager.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import tables, std/options
import waku/waku_lightpush/rpc

type
PeerId = string

ResponseQuality* = enum
BadResponse
GoodResponse

# Encode reputation indicator as Option[bool]:
# some(true) => GoodRep
# some(false) => BadRep
# none(bool) => unknown / not set
ReputationManager* = ref object
reputationOf*: Table[PeerId, Option[bool]]

proc init*(T: type ReputationManager): ReputationManager =
return ReputationManager(reputationOf: initTable[PeerId, Option[bool]]())

proc setReputation*(
manager: var ReputationManager, peer: PeerId, repValue: Option[bool]
) =
manager.reputationOf[peer] = repValue

proc getReputation*(manager: ReputationManager, peer: PeerId): Option[bool] =
if peer in manager.reputationOf:
result = manager.reputationOf[peer]
else:
result = none(bool)

# Evaluate the quality of a PushResponse by checking its isSuccess field
proc evaluateResponse*(response: PushResponse): ResponseQuality =
if response.isSuccess:
return GoodResponse
else:
return BadResponse

# Update reputation of the peer based on the quality of the response
proc updateReputationFromResponse*(
manager: var ReputationManager, peer: PeerId, response: PushResponse
) =
let respQuality = evaluateResponse(response)
case respQuality
of BadResponse:
manager.setReputation(peer, some(false)) # false => BadRep
of GoodResponse:
manager.setReputation(peer, some(true)) # true => GoodRep

0 comments on commit a4e92a3

Please sign in to comment.