From a3668b0968e4840656df2a17537b08d4ca4b750d Mon Sep 17 00:00:00 2001 From: Sergei Tikhomirov Date: Thu, 27 Jun 2024 17:07:28 +0200 Subject: [PATCH] feat: add txid-based eligibility proof check for incentivization PoC (#2816) --- tests/incentivization/test_eligibility.nim | 20 ++++----- tests/incentivization/test_poc.nim | 9 ++-- tests/incentivization/test_rpc_codec.nim | 16 ++++---- waku/incentivization/common.nim | 38 ++--------------- waku/incentivization/eligibility.nim | 26 ++++++++++++ waku/incentivization/protocol.nim | 5 ++- waku/incentivization/txid_proof.nim | 48 ++++++++++++++++++++++ 7 files changed, 104 insertions(+), 58 deletions(-) create mode 100644 waku/incentivization/eligibility.nim create mode 100644 waku/incentivization/txid_proof.nim diff --git a/tests/incentivization/test_eligibility.nim b/tests/incentivization/test_eligibility.nim index a20617ca2..c5c73a44a 100644 --- a/tests/incentivization/test_eligibility.nim +++ b/tests/incentivization/test_eligibility.nim @@ -4,21 +4,19 @@ import chronos import - ../../../waku/incentivization/[ - rpc,common - ] + ../../../waku/incentivization/[rpc, common, txid_proof] suite "Waku Incentivization Eligibility Testing": - asyncTest "check eligibility success": - var byteSequence: seq[byte] = @[1, 2, 3, 4, 5, 6, 7, 8] - let eligibilityProof = EligibilityProof(proofOfPayment: some(byteSequence)) + asyncTest "check eligibility success with a txid-based proof": + let eligibilityProof = genTxIdEligibilityProof(true) + let isValid = await txidEligiblityCriteriaMet(eligibilityProof) check: - isEligible(eligibilityProof) + isValid - asyncTest "check eligibility failure": - var byteSequence: seq[byte] = @[0, 2, 3, 4, 5, 6, 7, 8] - let eligibilityProof = EligibilityProof(proofOfPayment: some(byteSequence)) + asyncTest "check eligibility failure with a txid-based proof": + let eligibilityProof = genTxIdEligibilityProof(false) + let isValid = await txidEligiblityCriteriaMet(eligibilityProof) check: - not isEligible(eligibilityProof) + not isValid diff --git a/tests/incentivization/test_poc.nim b/tests/incentivization/test_poc.nim index 6677e7595..55c90f3c9 100644 --- a/tests/incentivization/test_poc.nim +++ b/tests/incentivization/test_poc.nim @@ -19,6 +19,7 @@ import common, client, protocol, + txid_proof ] @@ -73,14 +74,14 @@ suite "Waku Incentivization PoC Dummy Protocol": asyncTeardown: await allFutures(clientSwitch.stop(), serverSwitch.stop()) - asyncTest "incentivization PoC: dummy protocol with a valid eligibility proof": - let request = genDummyRequestWithEligibilityProof(true) + asyncTest "incentivization PoC: dummy protocol with a valid txid eligibility proof": + let request = genDummyRequestWithTxIdEligibilityProof(true) let response = await client.sendRequest(request, serverRemotePeerInfo) check: response.isOk() - asyncTest "incentivization PoC: dummy protocol client with an invalid eligibility proof": - let request = genDummyRequestWithEligibilityProof(false) + asyncTest "incentivization PoC: dummy protocol client with an invalid txid eligibility proof": + let request = genDummyRequestWithTxIdEligibilityProof(false) let response = await client.sendRequest(request, serverRemotePeerInfo) check: response.isErr() diff --git a/tests/incentivization/test_rpc_codec.nim b/tests/incentivization/test_rpc_codec.nim index 08daa1032..a3982747e 100644 --- a/tests/incentivization/test_rpc_codec.nim +++ b/tests/incentivization/test_rpc_codec.nim @@ -1,20 +1,22 @@ import std/options, - std/strscans, testutils/unittests, - chronicles, chronos, libp2p/crypto/crypto import - ../../../waku/incentivization/rpc, - ../../../waku/incentivization/rpc_codec, - ../../../waku/incentivization/common + ../../../waku/incentivization/[ + rpc, + rpc_codec, + common, + txid_proof, + eligibility + ] suite "Waku Incentivization Eligibility Codec": asyncTest "encode eligibility proof": - let eligibilityProof = genEligibilityProof(true) + let eligibilityProof = genTxIdEligibilityProof(true) let encoded = encode(eligibilityProof) let decoded = EligibilityProof.decode(encoded.buffer).get() check: @@ -28,7 +30,7 @@ suite "Waku Incentivization Eligibility Codec": eligibilityStatus == decoded asyncTest "encode dummy request": - let dummyRequest = genDummyRequestWithEligibilityProof(true) + let dummyRequest = genDummyRequestWithTxIdEligibilityProof(true) let encoded = encode(dummyRequest) let decoded = DummyRequest.decode(encoded.buffer).get() check: diff --git a/waku/incentivization/common.nim b/waku/incentivization/common.nim index 515caadf7..2112cc4fb 100644 --- a/waku/incentivization/common.nim +++ b/waku/incentivization/common.nim @@ -1,16 +1,16 @@ import std/options, std/strscans, + std/sequtils, testutils/unittests, chronicles, chronos, libp2p/crypto/crypto -import stew/results, chronos, libp2p/peerid +import stew/results, libp2p/peerid import - ../../../waku/incentivization/rpc, - ../../../waku/incentivization/rpc_codec + ../../../waku/incentivization/rpc const DummyCodec* = "/vac/waku/dummy/0.0.1" @@ -42,15 +42,6 @@ type DummyProtocolResult* = Result[void, DummyProtocolError] - -proc genEligibilityProof*(startsWithOne: bool): EligibilityProof = - let byteSequence: seq[byte] = ( - if startsWithOne: - @[1, 2, 3, 4, 5, 6, 7, 8] - else: - @[0, 2, 3, 4, 5, 6, 7, 8]) - EligibilityProof(proofOfPayment: some(byteSequence)) - proc genEligibilityStatus*(isEligible: bool): EligibilityStatus = if isEligible: EligibilityStatus( @@ -59,25 +50,4 @@ proc genEligibilityStatus*(isEligible: bool): EligibilityStatus = else: EligibilityStatus( statusCode: uint32(402), - statusDesc: some("Payment Required")) - -proc genDummyRequestWithEligibilityProof*(proofValid: bool, requestId: string = ""): DummyRequest = - let eligibilityProof = genEligibilityProof(proofValid) - result.requestId = requestId - result.eligibilityProof = eligibilityProof - -proc genDummyResponseWithEligibilityStatus*(proofValid: bool, requestId: string = ""): DummyResponse = - let eligibilityStatus = genEligibilityStatus(proofValid) - result.requestId = requestId - result.eligibilityStatus = eligibilityStatus - -proc dummyEligibilityCriteriaMet(eligibilityProof: EligibilityProof): bool = - # a dummy criterion: the first element of the proof byte array equals 1 - let proofOfPayment = eligibilityProof.proofOfPayment - if proofOfPayment.isSome: - return (proofOfPayment.get()[0] == 1) - else: - return false - -proc isEligible*(eligibilityProof: EligibilityProof): bool = - dummyEligibilityCriteriaMet(eligibilityProof) + statusDesc: some("Payment Required")) \ No newline at end of file diff --git a/waku/incentivization/eligibility.nim b/waku/incentivization/eligibility.nim new file mode 100644 index 000000000..fe6b90f74 --- /dev/null +++ b/waku/incentivization/eligibility.nim @@ -0,0 +1,26 @@ +import + std/options, + std/strscans, + std/sequtils, + testutils/unittests, + chronicles, + chronos, + libp2p/crypto/crypto + +import stew/results, libp2p/peerid + +import + ../../../waku/incentivization/rpc, + ../../../waku/incentivization/rpc_codec, + ../../../waku/incentivization/common, + ../../../waku/incentivization/txid_proof + + +proc isEligible*(eligibilityProof: EligibilityProof): Future[bool] {.async.} = + result = await txidEligiblityCriteriaMet(eligibilityProof) + +proc genDummyResponseWithEligibilityStatus*(proofValid: bool, requestId: string = ""): DummyResponse = + let eligibilityStatus = genEligibilityStatus(proofValid) + result.requestId = requestId + result.eligibilityStatus = eligibilityStatus + diff --git a/waku/incentivization/protocol.nim b/waku/incentivization/protocol.nim index 8dc16c7aa..89034e857 100644 --- a/waku/incentivization/protocol.nim +++ b/waku/incentivization/protocol.nim @@ -10,7 +10,8 @@ import ../waku_core, ./common, ./rpc_codec, - ./rpc + ./rpc, + ./eligibility logScope: topics = "waku incentivization PoC" @@ -29,7 +30,7 @@ proc handleRequest*( let dummyRequest = reqDecodeRes.get() let eligibilityProof = dummyRequest.eligibilityProof requestId = dummyRequest.requestId - isProofValid = isEligible(eligibilityProof) + isProofValid = await isEligible(eligibilityProof) let response = genDummyResponseWithEligibilityStatus(isProofValid, requestId) return response diff --git a/waku/incentivization/txid_proof.nim b/waku/incentivization/txid_proof.nim new file mode 100644 index 000000000..8d73d9ccb --- /dev/null +++ b/waku/incentivization/txid_proof.nim @@ -0,0 +1,48 @@ +import + std/options, + chronos, + web3, + stew/byteutils + +import ../../../waku/incentivization/rpc + +# a random confirmed txis (Sepolia) +const TxHashExisting* = TxHash.fromHex( + "0xc1be5f442d3688a8d3e4b5980a73f15e4351358e0f16e2fdd99c2517c9cf6270" + ) +const TxHashNonExisting* = TxHash.fromHex( + "0x0000000000000000000000000000000000000000000000000000000000000000" + ) + +const EthClient = "https://sepolia.infura.io/v3/470c2e9a16f24057aee6660081729fb9" + +proc genTxIdEligibilityProof*(txIdExists: bool): EligibilityProof = + let txHash: TxHash = ( + if txIdExists: + TxHashExisting + else: + TxHashNonExisting) + let txHashAsBytes = @(txHash.bytes()) + EligibilityProof(proofOfPayment: some(txHashAsBytes)) + +proc genDummyRequestWithTxIdEligibilityProof*(proofValid: bool, requestId: string = ""): DummyRequest = + let eligibilityProof = genTxIdEligibilityProof(proofValid) + result.requestId = requestId + result.eligibilityProof = eligibilityProof + +proc checkTxIdExists(txHash: TxHash): Future[bool] {.async.} = + let web3 = await newWeb3(EthClient) + try: + discard await web3.provider.eth_getTransactionByHash(txHash) + result = true + except ValueError as e: + result = false + await web3.close() + result + +proc txidEligiblityCriteriaMet*(eligibilityProof: EligibilityProof): Future[bool] {.async.} = + if eligibilityProof.proofOfPayment.isNone(): + return false + let txHash = TxHash.fromHex(byteutils.toHex(eligibilityProof.proofOfPayment.get())) + let txExists = await checkTxIdExists(txHash) + return txExists \ No newline at end of file