-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add txhash-based eligibility checks for incentivization PoC (#3166
) Implement data structures and tests for checking transaction eligibility based on tx hash. This work will be continues in future PRs. All code added in this PR is only used in tests. * feat: add simple txid-based eligibility check with hard-coded params (#3166) * use new proc to generate eligibility status Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> * minor fixes * add comments to clarify eligibility definition * use Address.fromHex conversion from eth-web3 * move isEligible to common * refactor: avoid result and unnecesary branching * define const for simple transfer gas usage * avoid unnecessary parentheses * chore: run nph linter manually * refactor, move all hard-coded constants to tests * use Result type in eligibility tests * use standard method of error handling * make try-block smaller * add a try-block in case of connection failure to web3 provider * make queries to web3 provider in parallel * move Web3 provider RPC URL into env variable * remove unused import * rename functions * use await in async proc Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> * add timeout to tx receipt query * parallelize queries for tx and txreceipt * make test txids non public Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use assert in txid i13n test Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use parentheses when calling verb-methods without arguments Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * remove unused import Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use init for stack-allocated objects * add txReceipt error message to error Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * introduce eligibility manager * [WIP] use Anvil for eligibility testing * add eligibility test with contract deployment tx * add eligibility test with contract call * add asyncSetup and asyncTeardown for eligibility tests * minor refactor * refactor tests for onchain group manager with asyncSetup and asyncTeardown * minor refactor * remove unnecessary defer in asyncTeardown Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * remove unnecessary call in test (moved to asyncTeardown) Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * add comment justidying the use of discard * rename file txid_proof to eligibility_manager --------- Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
- Loading branch information
1 parent
2942782
commit 505ec84
Showing
10 changed files
with
371 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
import ./test_rpc_codec | ||
import ./test_rpc_codec, ./test_poc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
{.used.} | ||
|
||
import | ||
std/[options], | ||
testutils/unittests, | ||
chronos, | ||
web3, | ||
stew/byteutils, | ||
stint, | ||
strutils, | ||
tests/testlib/testasync | ||
|
||
import | ||
waku/[node/peer_manager, waku_core], | ||
waku/incentivization/[rpc, eligibility_manager], | ||
../waku_rln_relay/[utils_onchain, utils] | ||
|
||
const TxHashNonExisting = | ||
TxHash.fromHex("0x0000000000000000000000000000000000000000000000000000000000000000") | ||
|
||
# Anvil RPC URL | ||
const EthClient = "ws://127.0.0.1:8540" | ||
|
||
const TxValueExpectedWei = 1000.u256 | ||
|
||
## Storage.sol contract from https://remix.ethereum.org/ | ||
## Compiled with Solidity compiler version "0.8.26+commit.8a97fa7a" | ||
|
||
const ExampleStorageContractBytecode = | ||
"6080604052348015600e575f80fd5b506101438061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea26469706673582212209a0dd35336aff1eb3eeb11db76aa60a1427a12c1b92f945ea8c8d1dfa337cf2264736f6c634300081a0033" | ||
|
||
contract(ExampleStorageContract): | ||
proc number(): UInt256 {.view.} | ||
proc store(num: UInt256) | ||
proc retrieve(): UInt256 {.view.} | ||
|
||
#[ | ||
// SPDX-License-Identifier: GPL-3.0 | ||
pragma solidity >=0.8.2 <0.9.0; | ||
/** | ||
* @title Storage | ||
* @dev Store & retrieve value in a variable | ||
* @custom:dev-run-script ./scripts/deploy_with_ethers.ts | ||
*/ | ||
contract Storage { | ||
uint256 number; | ||
/** | ||
* @dev Store value in variable | ||
* @param num value to store | ||
*/ | ||
function store(uint256 num) public { | ||
number = num; | ||
} | ||
/** | ||
* @dev Return value | ||
* @return value of 'number' | ||
*/ | ||
function retrieve() public view returns (uint256){ | ||
return number; | ||
} | ||
} | ||
]# | ||
|
||
proc setup( | ||
manager: EligibilityManager | ||
): Future[(TxHash, TxHash, TxHash, TxHash, TxHash, Address, Address)] {.async.} = | ||
## Populate the local chain (connected to via manager) | ||
## with txs required for eligibility testing. | ||
## | ||
## 1. Depoly a dummy contract that has a publicly callable function. | ||
## (While doing so, we confirm a contract creation tx.) | ||
## 2. Confirm these transactions: | ||
## - a contract call tx (eligibility test must fail) | ||
## - a simple transfer with the wrong receiver (must fail) | ||
## - a simple transfer with the wrong amount (must fail) | ||
## - a simple transfer with the right receiver and amount (must pass) | ||
|
||
let web3 = manager.web3 | ||
|
||
let accounts = await web3.provider.eth_accounts() | ||
web3.defaultAccount = accounts[0] | ||
let sender = web3.defaultAccount | ||
let receiverExpected = accounts[1] | ||
let receiverNotExpected = accounts[2] | ||
|
||
let txValueEthExpected = TxValueExpectedWei | ||
let txValueEthNotExpected = txValueEthExpected + 1 | ||
|
||
# wrong receiver, wrong amount | ||
let txHashWrongReceiverRightAmount = | ||
await web3.sendEthTransfer(sender, receiverNotExpected, txValueEthExpected) | ||
|
||
# right receiver, wrong amount | ||
let txHashRightReceiverWrongAmount = | ||
await web3.sendEthTransfer(sender, receiverExpected, txValueEthNotExpected) | ||
|
||
# right receiver, right amount | ||
let txHashRightReceiverRightAmount = | ||
await web3.sendEthTransfer(sender, receiverExpected, txValueEthExpected) | ||
|
||
let receipt = await web3.deployContract(ExampleStorageContractBytecode) | ||
let txHashContractCreation = receipt.transactionHash | ||
let exampleStorageContractAddress = receipt.contractAddress.get() | ||
let exampleStorageContract = | ||
web3.contractSender(ExampleStorageContract, exampleStorageContractAddress) | ||
|
||
let txHashContractCall = await exampleStorageContract.store(1.u256).send() | ||
|
||
return ( | ||
txHashWrongReceiverRightAmount, txHashRightReceiverWrongAmount, | ||
txHashRightReceiverRightAmount, txHashContractCreation, txHashContractCall, | ||
receiverExpected, receiverNotExpected, | ||
) | ||
|
||
suite "Waku Incentivization PoC Eligibility Proofs": | ||
## Tests for service incentivization PoC. | ||
## In a client-server interaction, a client submits an eligibility proof to the server. | ||
## The server provides the service if and only if the proof is valid. | ||
## In PoC, a txid serves as eligibility proof. | ||
## The txid reflects the confirmed payment from the client to the server. | ||
## The request is eligible if the tx is confirmed and pays the correct amount to the correct address. | ||
## The tx must also be of a "simple transfer" type (not a contract creation, not a contract call). | ||
## See spec: https://github.com/waku-org/specs/blob/master/standards/core/incentivization.md | ||
|
||
## Start Anvil | ||
let runAnvil {.used.} = runAnvil() | ||
|
||
var txHashWrongReceiverRightAmount, txHashRightReceiverWrongAmount, | ||
txHashRightReceiverRightAmount, txHashContractCreation, txHashContractCall: TxHash | ||
|
||
var receiverExpected, receiverNotExpected: Address | ||
|
||
var manager {.threadvar.}: EligibilityManager | ||
|
||
asyncSetup: | ||
manager = await EligibilityManager.init(EthClient) | ||
|
||
( | ||
txHashWrongReceiverRightAmount, txHashRightReceiverWrongAmount, | ||
txHashRightReceiverRightAmount, txHashContractCreation, txHashContractCall, | ||
receiverExpected, receiverNotExpected, | ||
) = await manager.setup() | ||
|
||
asyncTeardown: | ||
await manager.close() | ||
|
||
asyncTest "incentivization PoC: non-existent tx is not eligible": | ||
## Test that an unconfirmed tx is not eligible. | ||
|
||
let eligibilityProof = | ||
EligibilityProof(proofOfPayment: some(@(TxHashNonExisting.bytes()))) | ||
let isEligible = await manager.isEligibleTxId( | ||
eligibilityProof, receiverExpected, TxValueExpectedWei | ||
) | ||
check: | ||
isEligible.isErr() | ||
|
||
asyncTest "incentivization PoC: contract creation tx is not eligible": | ||
## Test that a contract creation tx is not eligible. | ||
|
||
let eligibilityProof = | ||
EligibilityProof(proofOfPayment: some(@(txHashContractCreation.bytes()))) | ||
let isEligible = await manager.isEligibleTxId( | ||
eligibilityProof, receiverExpected, TxValueExpectedWei | ||
) | ||
check: | ||
isEligible.isErr() | ||
|
||
asyncTest "incentivization PoC: contract call tx is not eligible": | ||
## Test that a contract call tx is not eligible. | ||
## This assumes a payment in native currency (ETH), not a token. | ||
|
||
let eligibilityProof = | ||
EligibilityProof(proofOfPayment: some(@(txHashContractCall.bytes()))) | ||
let isEligible = await manager.isEligibleTxId( | ||
eligibilityProof, receiverExpected, TxValueExpectedWei | ||
) | ||
check: | ||
isEligible.isErr() | ||
|
||
asyncTest "incentivization PoC: simple transfer tx is eligible": | ||
## Test that a simple transfer tx is eligible (if necessary conditions hold). | ||
|
||
let eligibilityProof = | ||
EligibilityProof(proofOfPayment: some(@(txHashRightReceiverRightAmount.bytes()))) | ||
let isEligible = await manager.isEligibleTxId( | ||
eligibilityProof, receiverExpected, TxValueExpectedWei | ||
) | ||
|
||
assert isEligible.isOk(), isEligible.error | ||
|
||
# Stop Anvil daemon | ||
stopAnvil(runAnvil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,22 @@ | ||
import | ||
std/options, | ||
std/strscans, | ||
testutils/unittests, | ||
chronicles, | ||
chronos, | ||
libp2p/crypto/crypto | ||
import std/options, testutils/unittests, chronos, libp2p/crypto/crypto, web3 | ||
|
||
import waku/incentivization/rpc, waku/incentivization/rpc_codec | ||
import waku/incentivization/[rpc, rpc_codec, common] | ||
|
||
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 = init(EligibilityStatus, true) | ||
let encoded = encode(eligibilityStatus) | ||
let decoded = EligibilityStatus.decode(encoded.buffer).get() | ||
check: | ||
esRpc == decoded | ||
eligibilityStatus == decoded |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.