# 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' ```