# RLN-attnets: Rate Limiting Nullifier utilizing Attestation Subnet for membership
see https://github.com/ethereum/consensus-specs/issues/2749
# Abstract
We propose a reputation circut for creating an RLN construct for the purposes of automating and regulating agent access to a service endpoint. This reputation circuit is derived from both attestation and sync subnet results. This calculated score is used to provide a congestion score of network latency, as the calculated attnet/subnet is a function of connected peer latency.
The drop probability decays exponentially (rather than linearly) when the system is not congested. As such, this would help the *drop* probability converge to 0 more quickly, while the controller ensures that it would eventually reach zero.
The decay parameter of 2% gives us a time constant around 50 * T_UPDATE.
Specifically, the ICRLN algorithm periodically adjusts the drop
probability every T_UPDATE interval:
## Notes
If a node's ENR indicated that it belonged to one or more persistent committees, then it was considered a validating node.
This bucketizes nodes by the number of subnets they are subscribed to. This info can be used to estimate how many validators a particular node hosts.
### Validator Clustering
the subnet subscriptions are used to bucketize nodes. If a node has < 64 subnet subscriptions, then it is '+'; otherwise, '-'. A good rule of thumb to use when interpreting this chart is:
> '+' validators probably more fairly evenly spread across many nodes.
> '-' validators probably more likely hosted on just a few nodes.
## Overview
RLN enforcing utilizing ENR according to subscribed attestation subnets
For congestion detection, this is based on the queuing latency instead of the queue length. Furthermore, we can also use the derivative (rate of change) of the queuing latency to help determine congestion levels and an appropriate response. Queuing latency is derived from connection churn value/turnover rate of connected peers.
## Attnet Model
## WIP
```javascript
// ENR_FORK_ID:
// DISCOVERY_PEER2.getPersistentAttestationSubnets(),
// DISCOVERY_PEER1.getSyncCommitteeSubnets(),
// ATTESTATION_SUBNET_ENR_FIELD
// SYNC_COMMITTEE_SUBNET_ENR_FIELD
// ATTESTATION_SUBNET_COUNT
// PERSISTENT_ATTESTATION_SUBNETS
const SYNC_COMMITTEE_SUBNETS
const ETH2_ENR_FIELD = ''
PUB_KEY = function Bytes.fromHexString("0x0330FC08314CDD799C1687FFC998249A0342105B9AF300A922F56040DF6E28741C");
public readonly PEER_ID = "16Uiu2HAmFxCpRh2nZevFR3KGXJ3jhpixMYFSuawqKZyZYHrYoiK5";
const NODE_ID: new.LibP2PNodeId(PeerId.fromBase58(PEER_ID));
const ATTESTATION_SUBNET_ENR_FIELD = "attnets";
const FORK_RETRY_DELAY_SECONDS = 10; // in sec
const FORK_REFRESH_TIME_SECONDS = 5; // in sec
const MAX_SUBNET_SCORE = 1000;
const SCORE_SUBNET_CANDIDATE_PEER = { `
value = numberOfOtherSubscribers + 1;
return MAX_SUBNET_SCORE / (value * value);
`}
// Networking
const GOSSIP_MAX_SIZE = 1048576; // bytes
const MAX_CHUNK_SIZE = 1048576; // bytes
const ATTESTATION_SUBNET_COUNT = 64;
const TTFB_TIMEOUT = 5; // in sec
const RESP_TIMEOUT = 10; // in sec
const ATTESTATION_PROPAGATION_SLOT_RANGE = 32;
const MAXIMUM_GOSSIP_CLOCK_DISPARITY = 500; // in ms
class DiscoveryPeer {(
/* Bytes */
nodeRecord.get(EnrField.PKEY_SECP256K1),
address,
enrForkId,
persistentAttestationSubnets,
syncCommitteeSubnets
)};
```
The drop probability decays exponentially (rather than linearly) when the network is not congested.
### Tuning
calculate drop probability ICRLN > drop_probability
```go
// pseudo code
p = alpha * (current_qdelay - QDELAY_REF) +
beta * (current_qdelay - ICRLN->qdelay_old_);
if (ICRLN->drop_prob_ < 0.000001) {
p /= 2048;
} else if (ICRLN->drop_prob_ < 0.00001) {
p /= 512;
} else if (ICRLN->drop_prob_ < 0.0001) {
p /= 128;
} else if (ICRLN->drop_prob_ < 0.001) {
p /= 32;
} else if (ICRLN->drop_prob_ < 0.01) {
p /= 8;
} else if (ICRLN->drop_prob_ < 0.1) {
p /= 2;
} else {
p = p;
}
ICRLN->drop_prob_ += p;
```
Then we decay the drop probability exponentially:
```go
if (current_qdelay == 0 && ICRLN->qdelay_old_ == 0) {
// 1 - 1/64 is sufficient
ICRLN->drop_prob_ = ICRLN->drop_prob_ * 0.98;
```
and bound the drop probability:
```go
if (ICRLN->drop_prob_ < 0)
ICRLN->drop_prob_ = 0.0
if (ICRLN->drop_prob_ > 1)
ICRLN->drop_prob_ = 1.0
```
and store the current latency value:
```js
readonly const valICRLN: 'ICRLN > qdelay_old_ = current_qdelay'
```