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

Add WAKU2-RLN-CONTRACT spec for mainnet deployment #30

Merged
merged 28 commits into from
Aug 20, 2024
Merged
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d2d5352
add first version of WAKU2-RLN-CONTRACT spec
s-tikhomirov Aug 2, 2024
7ea898b
Apply suggestions from code review
s-tikhomirov Aug 5, 2024
7df465d
address some suggestions
s-tikhomirov Aug 5, 2024
d84ac43
remove future work; minor fixes
s-tikhomirov Aug 7, 2024
5f663e3
clarify path to immutability
s-tikhomirov Aug 7, 2024
d61d6b0
major edit; add table of available functionalities
s-tikhomirov Aug 8, 2024
471b479
add state transition diagram
s-tikhomirov Aug 8, 2024
c816007
major edit incl RFC-speak
s-tikhomirov Aug 9, 2024
4a685cd
specify counting total rate limit
s-tikhomirov Aug 9, 2024
9a6114f
split Erased state on whether deposit is withdrawn
s-tikhomirov Aug 9, 2024
03e868c
edit, unify terminology
s-tikhomirov Aug 12, 2024
6d3b946
rename membership owner to holder (avoid confusion with contract owner)
s-tikhomirov Aug 12, 2024
1fe5dfc
structure edits
s-tikhomirov Aug 12, 2024
7ff2c60
minor edits
s-tikhomirov Aug 12, 2024
1d52731
minor fix
s-tikhomirov Aug 12, 2024
9eab39c
fix typo
s-tikhomirov Aug 13, 2024
3cac3f0
minor edits
s-tikhomirov Aug 14, 2024
fead1f5
address some suggestions
s-tikhomirov Aug 15, 2024
2f45184
Update standards/core/rln-contract.md
s-tikhomirov Aug 15, 2024
554758a
clarify pricing parameter
s-tikhomirov Aug 15, 2024
50d7272
Update standards/core/rln-contract.md
s-tikhomirov Aug 16, 2024
2c65185
separate recommendations for contract vs app devs
s-tikhomirov Aug 16, 2024
a178c48
change price of unit rate limit to 0.05 USD
s-tikhomirov Aug 16, 2024
1d97db4
raise max total rate limit to 160 msg/epoch
s-tikhomirov Aug 19, 2024
9caa26c
less strict MUST usage (referring to RLN Relay spec)
s-tikhomirov Aug 19, 2024
ecdd7b3
define holder/keeper distinction
s-tikhomirov Aug 19, 2024
22d86f3
limit the rate limit of one membership to 600 msg / epoch
s-tikhomirov Aug 19, 2024
0d60b6f
style edits
s-tikhomirov Aug 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 297 additions & 0 deletions standards/core/rln-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,297 @@
---
title: WAKU2-RLN-CONTRACT
name: Waku2 RLN Contract Specification
category: Standards Track
tags: [waku/core-protocol]
editor: Sergei Tikhomirov <[email protected]>
contributors:
---

## Abstract

This document specifies RLN membership management in the context of mainnet deployment of the RLN smart contract, in particular:
- membership-related contract functionality;
- contract parameters for the initial mainnet deployment;
- contract governance and upgradability.

We only consider contract functionality relevant for membership management.
The document might later evolve into a full-fledged contract specification.

## Background

Rate-Limiting Nullifier (RLN) is a ZK-based gadget used in Waku.
RLN provides a privacy-preserving way to limit each user's burden on the network.
The RLN smart contract is the core element of RLN architecture.
Users interact with the contract to manage their memberships,
as well as to get the data necessary for proof generation and verification.

To relay a message:
- the sender MUST register a membership in a smart contract;
- the sender MUST attach a ZK-proof of membership to every message;
- each relaying node MUST drop the message if:
- the proof is invalid; or
- the sender has exceeded their rate limit within the current epoch.

RLN is only deployed on Sepolia testnet as of August 2024.
This document aims to outline the path to its mainnet deployment.

## Membership lifecycle

Any existing membership MUST always be in exactly one of the following states:
- _Active_;
- _GracePeriod_;
- _Expired_;
- _ErasedAwaitsWithdrawal_;
- _Erased_.

```mermaid
graph TD;
NonExistent --> |"register"| Active;
Active --> |"time `T` passed"| GracePeriod;
GracePeriod --> |"extend"| Active;
GracePeriod --> |"time `G` passed"| Expired;
GracePeriod --> |"withdraw"| Erased;
Expired --> |"withdraw"| Erased;
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved
Expired --> |"another membership reuses slot"| ErasedAwaitsWithdrawal;
ErasedAwaitsWithdrawal --> |"withdraw"| Erased;
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved

```

State updates triggered by a transaction MUST be applied immediately.
State updates defined by time progression MAY be applied lazily.
When providing any membership-specific functionality, the contract MUST:
- check whether the state of the membership involved is up-to-date;
- if necessary, update the membership state;
- process the transaction in accordance with the up-to-date membership state.

Memberships MUST be included in the RLN tree according to the following table:

| State | Included in the tree |
| ---------------------- | -------------------- |
| Active | Yes |
| GracePeriod | Yes |
| Expired | Yes |
| ErasedAwaitsWithdrawal | No |
| Erased | No |


Memberships MUST NOT be transferable.
One Ethereum address MAY register multiple memberships.
One Waku node MAY manage multiple memberships
(this functionality is not yet implemented as of August 2024).

## Contract functionalities

The contract MUST provide the following functionalities:
- register a membership;
- extend a membership;
- withdraw a deposit.

Availability of membership-specific functionalities MUST be as follows:

| | Active | Grace Period | Expired | ErasedAwaitsWithdrawal | Erased |
| --------------------- | ------ | ------------ | ------- | ---------------------- | ------ |
| Send a message | Yes | Yes | Yes | No | No |
| Extend the membership | No | Yes | No | No | No |
| Withdraw the deposit | No | Yes | Yes | Yes | No |
### Governance and upgradability

At initial mainnet deployment, the contract MUST have an _Owner_ with the following additional functionalities:
- change any of the modifiable parameters, as listed in the Parameter table;
- disable any of the following contract functionalities:
- register a membership;
- extend a membership;
- (TBD) withdraw a deposit.

At some point, the _Owner_ SHOULD renounce their privileges, and the contract MUST become immutable.
Further upgrades, if necessary, SHOULD be done by deploying a new contract and migrating the membership set.

### Register a membership

Membership registration is subject to the following conditions:
- if there are _Expired_ memberships in the contract, the new membership MUST overwrite an expired membership;
- the new membership SHOULD overwrite the membership that had been _Expired_ for the longest time;
- if an _Expired_ membership A is overwritten by membership B:
- membership B MUST transition to _ErasedAwaitsWithdrawal_;
- the current total rate limit MUST be decremented by the rate limit of membership B;
- the contract MUST take all necessary steps to ensure that the owner of membership B can withdraw their deposit later;
- registration MUST fail if the total rate limit of _Active_, _GracePeriod_, and _Expired_ memberships, including the one being created, would exceed the limit;
- registration MUST fail if the requested rate limit for the new membership is lower than the minimal allowed rate limit;
- the user MUST lock-up a deposit to register a membership;
- the user MUST specify the rate limit of the new membership;
- the size of the deposit MUST be calculated depending on the requested rate limit;
- in case of successful registration:
- the new membership MUST be in the _Active_ state;
- the current total rate limit MUST be incremented by the rate limit of the new membership;
- a newly created membership MUST have an expiration time `T` and a grace period `G` (see RECOMMENDED parameter values below).

### Send a message

Sending messages is handled by Waku Relay nodes, not by the RLN smart contract.
For completeness, sending messages is mentioned here as the key Waku functionality.
The full specification of Relay node behavior is out of scope for this document.

A Relay node MUST relay a message unless:
- the message is committed to a different epoch than the current epoch; or
- the user has exceed their allowed rate limit for the current epoch; or
- the RLN proof fails to prove that the message sender owns an existing membership.

### Extend a membership

Extending a membership is subject to the following condition:
- extension MUST fail if the membership is in any state other than _GracePeriod_;
- the membership owner MUST be able to extend the membership;
- any user except the membership owner MUST NOT be able to extend the membership;
- after a successful extension, the membership MUST become _Active_.

Owning a membership means controlling the private key from which the RLN commitment ID (i.e., public key) was derived.

### Withdraw the deposit

Deposit withdrawal is subject to the following conditions:
- the owner of a membership MUST be able to withdraw their deposit;
- any user except the membership owner MUST NOT be able to withdraw its deposit;
- a deposit MUST be withdrawn in full;
- a withdrawal MUST fail if the membership is not in _GracePeriod_, _Expired_, or _ErasedAwaitsWithdrawal_;
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved
- any withdrawal MUST move the membership to _Erased_.

## Implementation Suggestions

The current version of the contract (RLNv2) is deployed on Sepolia testnet ([source code](https://github.com/waku-org/waku-rlnv2-contract/blob/main/src/WakuRlnV2.sol)).

The RECOMMENDED parameter values for the initial mainnet deployment are listed in the following table.
All parameter values MUST be modifiable by the contract _Owner_.

| Parameter | Symbol | Value | Units |
| ------------------------------------------- | --------- | ------- | ---------------------------------- |
| Epoch length | `epoch` | `10` | minutes |
| Maximum total rate limit of all memberships | `R_{max}` | `20000` | messages per `epoch` |
| Minimal rate limit of one membership | `r_{min}` | `20` | messages per `epoch` |
| Price of `1` message per epoch | `p_u` | `0.01` | `USD` per one period of length `T` |
| Membership expiration term | `T` | `90` | days |
| Membership grace period | `G` | `30` | days |
| Accepted tokens | | `DAI` | |
| Reference currency | | `USD` | |
| Pricing function | | linear | |

Applications MAY suggest the following rate limits to their users:
- `20` messages per epoch as low-tier;
- `200` messages per epoch as mid-tier;
- `600` messages per epoch as high-tier.

The user-facing application SHOULD save the expiration date in its local keystore during membership registration,
and notify the user when their membership is about to expire.

## Q&A

### Why can't I withdraw a deposit from an _Active_ membership?

The rationale for this limitation is to prevent an undesirable usage pattern where users make deposits and withdrawals in short succession.
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved

### Why can't I extend an _Active_ membership?

Memberships can only be extended during _GracePeriod_.
We do not allow extending an _Active_ membership.
The rationale is that if the _Owner_ changes some contract parameters (e.g., for security purposes),
users with extended memberships will not be affected by the changes for a long time.

### What if I don't extend my membership within its _GracePeriod_?

The user who does not extend their _GracePeriod_ membership, assumes the risk of the membership being overwritten at any moment.
We expect that most users would not want to take that risk and would either extend their memberships or withdraw their deposits.

### Can I send messages when my membership is _Expired_?

An _Expired_ membership allows sending messages for some time.

Sending messages is managed by Relay nodes, not by RLN contract.
The RLN proof that message senders provide to Relay nodes only proves whether the sender owns _some_ membership included in the RLN tree.
The sender cannot prove the state of that membership.

_Expired_ memberships are not erased from the tree proactively.
An _Expired_ membership is only erased when either a new membership overwrites it, or when its deposit is withdrawn.
After a membership is erased, it can no longer be used for sending messages.

### Will my deposit be slashed if I exceed the rate limit?

The aim of the deposit initially is to protect the network from denial-of-service attacks with bandwidth capping.
The current version of RLN does not involve slashing.

### Do I need an extra deposit to extend a membership?

Membership extension requires no additional deposit.
The opportunity cost of locked-up capital plus gas fees for extension transactions make extensions non-free, which is sufficient for the initial mainnet deployment.

### Why this particular epoch length?

Epoch length is a global parameter set in the smart contract.
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved
Rate limits are defined in terms of the maximum allowed messages per epoch.
There is a trade-off between short and long epochs.

On the one hand, longer epochs allow for better accommodating short-term usage peaks.
Peaks tend to average out over longer time periods,
which allows us to reason about network utilization on a longer time scale.

On the other hand, long epochs increases memory requirements for Relay nodes.
Each message contains a nullifier that proves its validity in terms of RLN.
Each Relay node must keeps in memory a nullifier log for the current epoch.
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved

We chose an epoch length of `10` minutes as a reasonable middle-ground.
Each nullifier plus metadata is `128` bytes (per message).
With a `10`-minute epoch, one high-tier user with a `1` message per second rate limit generates up to `600 * 128 / 1024 = 75 KiB` of nullifier log data per epoch.
This corresponds to:
- for 1000 users: approximately `73 MiB`;
- for 10 thousand users: approximately `732 MiB`.

### Why is there a cap on the total rate limit?

Total network bandwidth is a limited resource.
We want to cap the total rate limit, at least in the initial mainnet deployment, to avoid overstretching the network's capabilities.

### Why is there a minimal rate limit?

The minimal rate limit prevents an attack where someone registers a large number of memberships with a tiny rate limit each, causing the RLN tree to contain too many elements.

### Are there bulk discounts for high-rate memberships?

For the initial mainnet deployment, membership price is linearly proportional to its rate limit.
We choose this pricing scheme for simplicity.
In other words, there are no bulk discounts.
High-rate memberships are arguably more efficient but can incentivize centralization.
Finding a pricing scheme with the right trade-off remains subject for future work.

### Why only accept DAI?

When choosing a token to accept, we considered the following criteria:
- a stablecoin, as USD-denominated pricing is familiar for users and requires no oracle;
- popular, high liquidity;
- preferably decentralized;
- with a reasonably good track record w.r.t. censorship.

Based on these criteria, we chose DAI for the initial mainnet deployment.
Other tokens may be added in the future.

## Security / Privacy Considerations

Issuing membership-specific transactions (e.g., membership extension and deposit withdrawal) publicly links it to an Ethereum address.
s-tikhomirov marked this conversation as resolved.
Show resolved Hide resolved
Note that this does not degrade the privacy of the relayed messages.

To produce an RLN proof, a message sender must obtain a Merkle proof for their RLN membership.
One way to obtain this proof is to request it from the RLN smart contract.
Requesting a proof through a third-party RPC provider may endanger the sender's privacy.
The provider would be able to link the requester's Ethereum address and the RLN membership with the corresponding API key.

## Copyright

Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

## References

- [Rate-Limiting Nullifier](https://rate-limiting-nullifier.github.io/rln-docs/)
- [11/WAKU2-RELAY](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md)
- [17/WAKU2-RLN-RELAY](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md)





Loading