Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add incentivization PoC for RLNaaS in Lightpush #3166

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion tests/incentivization/test_all.nim
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import ./test_rpc_codec
import
./test_rpc_codec,
./test_poc
59 changes: 59 additions & 0 deletions tests/incentivization/test_poc.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{.used.}

import
std/[options, strscans],
testutils/unittests,
chronicles,
chronos,
libp2p/crypto/crypto,
web3

import
waku/[node/peer_manager, waku_core],
../testlib/[assertions, wakucore, testasync, futures, testutils],
waku/incentivization/[rpc, rpc_codec, common, txid_proof, eligibility]

# All txids from Ethereum Sepolia testnet
const TxHashNonExisting* =
TxHash.fromHex("0x0000000000000000000000000000000000000000000000000000000000000000")
const TxHashContractCreation* =
TxHash.fromHex("0xa2e39bee557144591fb7b2891ef44e1392f86c5ba1fc0afb6c0e862676ffd50f")
const TxHashContractCall* =
TxHash.fromHex("0x2761f066eeae9a259a0247f529133dd01b7f57bf74254a64d897433397d321cb")
const TxHashSimpleTransfer* =
TxHash.fromHex("0xa3985984b2ec3f1c3d473eb57a4820a56748f25dabbf9414f2b8380312b439cc")

const EthClient = "https://sepolia.infura.io/v3/470c2e9a16f24057aee6660081729fb9"

suite "Waku Incentivization PoC Eligibility Proofs":

asyncTest "incentivization PoC: non-existent tx is not eligible":
let eligibilityProof =
EligibilityProof(proofOfPayment: some(@(TxHashNonExisting.bytes())))
let txIsEligible = await isEligible(eligibilityProof, EthClient)
check:
not txIsEligible

asyncTest "incentivization PoC: contract creation tx is not eligible":
let eligibilityProof =
EligibilityProof(proofOfPayment: some(@(TxHashContractCreation.bytes())))
let txIsEligible = await isEligible(eligibilityProof, EthClient)
check:
not txIsEligible

asyncTest "incentivization PoC: contract call tx is not eligible":
# note: assuming payment in native currency (ETH), not a token
let eligibilityProof =
EligibilityProof(proofOfPayment: some(@(TxHashContractCall.bytes())))
let txIsEligible = await isEligible(eligibilityProof, EthClient)
check:
not txIsEligible

asyncTest "incentivization PoC: simple transfer tx is eligible":
let eligibilityProof =
EligibilityProof(proofOfPayment: some(@(TxHashSimpleTransfer.bytes())))
let txIdExists = await isEligible(eligibilityProof, EthClient)
check:
txIdExists

# TODO: add tests for simple transfer txs with wrong amount and wrong receiver
43 changes: 35 additions & 8 deletions tests/incentivization/test_rpc_codec.nim
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import
std/options,
std/strscans,
testutils/unittests,
chronicles,
chronos,
libp2p/crypto/crypto
libp2p/crypto/crypto,
web3

import waku/incentivization/rpc, waku/incentivization/rpc_codec
import
waku/incentivization/[
rpc,
rpc_codec,
common,
txid_proof,
eligibility
]

#[
let txHash = TxHash.fromHex(
"0x0000000000000000000000000000000000000000000000000000000000000000"
)
let txHashAsBytes = @(txHash.bytes())
]#

suite "Waku Incentivization Eligibility Codec":
asyncTest "encode eligibility proof":

asyncTest "encode eligibility proof from bytes":
# FIXME: remove this test?
var byteSequence: seq[byte] = @[1, 2, 3, 4, 5, 6, 7, 8]
let epRpc = EligibilityProof(proofOfPayment: some(byteSequence))
let encoded = encode(epRpc)
let decoded = EligibilityProof.decode(encoded.buffer).get()
check:
epRpc == decoded

asyncTest "encode eligibility proof from txid":
let txHash = TxHash.fromHex(
"0x0000000000000000000000000000000000000000000000000000000000000000")
let txHashAsBytes = @(txHash.bytes())
let eligibilityProof = EligibilityProof(proofOfPayment: some(txHashAsBytes))
let encoded = encode(eligibilityProof)
let decoded = EligibilityProof.decode(encoded.buffer).get()
check:
eligibilityProof == decoded

asyncTest "encode eligibility status":
let esRpc = EligibilityStatus(statusCode: uint32(200), statusDesc: some("OK"))
let encoded = encode(esRpc)
let eligibilityStatus = genEligibilityStatus(true)
let encoded = encode(eligibilityStatus)
let decoded = EligibilityStatus.decode(encoded.buffer).get()
check:
esRpc == decoded
eligibilityStatus == decoded


23 changes: 23 additions & 0 deletions waku/incentivization/common.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import
std/options,
std/strscans,
std/sequtils,
testutils/unittests,
chronicles,
chronos,
libp2p/crypto/crypto

import stew/results, libp2p/peerid

import
waku/incentivization/rpc

proc genEligibilityStatus*(isEligible: bool): EligibilityStatus =
if isEligible:
EligibilityStatus(
statusCode: uint32(200),
statusDesc: some("OK"))
else:
EligibilityStatus(
statusCode: uint32(402),
statusDesc: some("Payment Required"))
20 changes: 20 additions & 0 deletions waku/incentivization/eligibility.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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, ethClient: string): Future[bool] {.async.} =
result = await txidEligiblityCriteriaMet(eligibilityProof, ethClient)
2 changes: 1 addition & 1 deletion waku/incentivization/rpc.nim
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import json_serialization, std/options
import ../waku_core
import waku/waku_core

# Implementing the RFC:
# https://github.com/vacp2p/rfc/tree/master/content/docs/rfcs/73
Expand Down
2 changes: 2 additions & 0 deletions waku/incentivization/rpc_codec.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import std/options
import ../common/protobuf, ../waku_core, ./rpc

const DefaultMaxRpcSize* = -1

# Codec for EligibilityProof

proc encode*(epRpc: EligibilityProof): ProtoBuffer =
Expand Down
53 changes: 53 additions & 0 deletions waku/incentivization/txid_proof.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import std/options, chronos, web3, stew/byteutils, stint

import waku/incentivization/rpc

proc checkTxIdIsEligible(txHash: TxHash, ethClient: string): Future[bool] {.async.} =
let web3 = await newWeb3(ethClient)
try:
let tx = await web3.provider.eth_getTransactionByHash(txHash)
echo tx
let txReceipt = await web3.getMinedTransactionReceipt(txHash)
echo txReceipt
result = true
echo "got tx and tx receipt"
if result:
# check that it is not a contract creation tx
let toAddressOption = txReceipt.to
let isContractCreationTx = toAddressOption.isNone
if isContractCreationTx:
echo "not eligible: contract creation tx!"
result = false
else:
# check that it is a simple transfer (not a contract call)
# a simple transfer uses 21000 gas
let gasUsed = txReceipt.gasUsed
let isSimpleTransferTx = (gasUsed == Quantity(21000))
echo "isSimpleTransferTx:" & $isSimpleTransferTx
if not isSimpleTransferTx:
result = false
else:
# check that the amount is "as expected" (hard-coded for now)
let txValue = tx.value
let hasExpectedValue = (txValue == 200500000000005063.u256)
echo "hasExpectedValue:" & $hasExpectedValue

# check that the to address is "as expected" (hard-coded for now)
let toAddress = toAddressOption.get()
let hasExpectedToAddress = (toAddress == address"0x5e809a85aa182a9921edd10a4163745bb3e36284")
echo "hasExpectedToAddress:" & $hasExpectedToAddress

result = true
except ValueError as e:
result = false
await web3.close()
result

proc txidEligiblityCriteriaMet*(
eligibilityProof: EligibilityProof, ethClient: string
): Future[bool] {.async.} =
if eligibilityProof.proofOfPayment.isNone():
return false
let txHash = TxHash.fromHex(byteutils.toHex(eligibilityProof.proofOfPayment.get()))
let txExists = await checkTxIdIsEligible(txHash, ethClient)
return txExists
Loading