mirror of https://github.com/waku-org/nwaku.git
feat: add simple txid-based eligibility check with hard-coded params (#3166)
This commit is contained in:
parent
6627e34e52
commit
a3bef8150d
|
@ -1 +1,3 @@
|
|||
import ./test_rpc_codec
|
||||
import
|
||||
./test_rpc_codec,
|
||||
./test_poc
|
||||
|
|
|
@ -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
|
|
@ -1,25 +1,35 @@
|
|||
import
|
||||
std/options,
|
||||
std/strscans,
|
||||
testutils/unittests,
|
||||
chronicles,
|
||||
chronos,
|
||||
libp2p/crypto/crypto
|
||||
libp2p/crypto/crypto,
|
||||
web3
|
||||
|
||||
import
|
||||
waku/incentivization/[
|
||||
rpc,
|
||||
rpc_codec,
|
||||
common
|
||||
]
|
||||
|
||||
import waku/incentivization/rpc, waku/incentivization/rpc_codec
|
||||
|
||||
suite "Waku Incentivization Eligibility Codec":
|
||||
asyncTest "encode eligibility proof":
|
||||
var byteSequence: seq[byte] = @[1, 2, 3, 4, 5, 6, 7, 8]
|
||||
let epRpc = EligibilityProof(proofOfPayment: some(byteSequence))
|
||||
let encoded = encode(epRpc)
|
||||
|
||||
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:
|
||||
epRpc == decoded
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import std/options
|
||||
|
||||
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"))
|
|
@ -0,0 +1,6 @@
|
|||
import std/options, chronos
|
||||
|
||||
import waku/incentivization/[rpc, txid_proof]
|
||||
|
||||
proc isEligible*(eligibilityProof: EligibilityProof, ethClient: string): Future[bool] {.async.} =
|
||||
result = await txidEligiblityCriteriaMet(eligibilityProof, ethClient)
|
|
@ -1,5 +1,4 @@
|
|||
import json_serialization, std/options
|
||||
import ../waku_core
|
||||
import std/options
|
||||
|
||||
# Implementing the RFC:
|
||||
# https://github.com/vacp2p/rfc/tree/master/content/docs/rfcs/73
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import std/options
|
||||
import ../common/protobuf, ../waku_core, ./rpc
|
||||
|
||||
const DefaultMaxRpcSize* = -1
|
||||
|
||||
# Codec for EligibilityProof
|
||||
|
||||
proc encode*(epRpc: EligibilityProof): ProtoBuffer =
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import std/options, chronos, web3, stew/byteutils, stint, strutils
|
||||
|
||||
import waku/incentivization/rpc
|
||||
|
||||
|
||||
# Function to convert a hex string to Address
|
||||
proc toAddress*(hexStr: string): Address =
|
||||
# Remove the "0x" prefix if it exists
|
||||
let cleaned = if hexStr.startsWith("0x"): hexStr[2..^1] else: hexStr
|
||||
|
||||
# Ensure the length is exactly 40 characters (20 bytes)
|
||||
if cleaned.len != 40:
|
||||
raise newException(ValueError, "Invalid hexadecimal string length for Address")
|
||||
|
||||
var arr: array[20, byte]
|
||||
for i in 0 ..< 20:
|
||||
let byteValue = cleaned[i * 2 ..< i * 2 + 2] # Get two hex characters
|
||||
arr[i] = byte(parseHexInt(byteValue))
|
||||
|
||||
result = Address(arr)
|
||||
|
||||
|
||||
proc checkTxIdIsEligible(txHash: TxHash, ethClient: string): Future[bool] {.async.} =
|
||||
let web3 = await newWeb3(ethClient)
|
||||
try:
|
||||
let tx = await web3.provider.eth_getTransactionByHash(txHash)
|
||||
let txReceipt = await web3.getMinedTransactionReceipt(txHash)
|
||||
result = true
|
||||
if result:
|
||||
# check that it is not a contract creation tx
|
||||
let toAddressOption = txReceipt.to
|
||||
let isContractCreationTx = toAddressOption.isNone
|
||||
if isContractCreationTx:
|
||||
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))
|
||||
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)
|
||||
# check that the to address is "as expected" (hard-coded for now)
|
||||
let toAddress = toAddressOption.get()
|
||||
let hasExpectedToAddress = (toAddress == toAddress("0x5e809a85aa182a9921edd10a4163745bb3e36284"))
|
||||
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…
Reference in New Issue