diff --git a/tests/incentivization/test_all.nim b/tests/incentivization/test_all.nim index 756db896d..4657ea0d3 100644 --- a/tests/incentivization/test_all.nim +++ b/tests/incentivization/test_all.nim @@ -1 +1 @@ -import ./test_rpc_codec, ./test_poc +import ./test_rpc_codec, ./test_poc_eligibility, ./test_poc_reputation diff --git a/tests/incentivization/test_poc.nim b/tests/incentivization/test_poc_eligibility.nim similarity index 100% rename from tests/incentivization/test_poc.nim rename to tests/incentivization/test_poc_eligibility.nim diff --git a/tests/incentivization/test_poc_reputation.nim b/tests/incentivization/test_poc_reputation.nim new file mode 100644 index 000000000..b35c4b92f --- /dev/null +++ b/tests/incentivization/test_poc_reputation.nim @@ -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) diff --git a/waku/incentivization/reputation_manager.nim b/waku/incentivization/reputation_manager.nim new file mode 100644 index 000000000..d5097b711 --- /dev/null +++ b/waku/incentivization/reputation_manager.nim @@ -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