There is a generalized usecase for the ability for the Lido protocol (at various levels, from the Staking Router, to Modules, to Node Operators (or Clusters) themselves) to have functionality to discern between different types (i.e. classifications related to shape, size, properties) of Node Operators (NOs). The abilty to discern between different types of NOs would allow for the protocol to treat NO types differently based on certain requirements or criteria.
This would be immediately useful for things like allowing for different risk profiles of Operators who have something at stake (e.g. Proof of Reputation, or Collateral, etc) vs permissionless operators who may have less at stake, or where it is difficult to discern whether an Operator is a Sybil or not, etc. Based on these different risk profiles, modules could tailor their functionality based on the idea that NOs may have a "default" type, and then, through some sort of mechanism, NOs could be "classified" in order to be allowed to interact with the module in a different way, or receive different perks (or penalties) based on their characteristics or performance. This would allow for a module to explicitly discern between (likely) Independent Operators and Unknown or Professionals for example, allowing one module to serve all these categories of NOs instead of having to create and target different modules for different NO types.
In general, there should (eventually) be a consistent way for the Staking Router and the Modules to understand an NO type. This could be enabled by a "global" NO registry, which is currently not a thing. Until such a time, Modules can reason about NO types "locally". Since CSMv2 is currently in development, we can consider improving upon an already existing mechanism in CSMv1 to enable this NO identification process and use it as a technical mechanism that other module bases can also benefit from.
In CSM v1, there exists a crude mechanism to discern two different types of Node Operators: those eligible for Early Adoption (basically a proxy for likely Independent Operators and CSM testnet users), and everyone else. This was enabled at a technical level through the use of the bonding curve functionality in CSM (i.e. creating a second bonding curve usable by EAers) in conjunction with the EarlyAdopters mechanism. This general mechanism can be abstracted upon for CSM v2 to enable very rich differentation between different types, and allow CSM v2 to grow into a permissionless module with very strong scaling potential with minimal changes required to the core aspects of the module, instead tweaking NO-type-specific configurations at the edges. In CSM code, this NOType
can be inferred by using a NO's bondCurveId
as a proxy. In CSMv2, we could carry this forward but attach an abstracted system of perks and safety mechanisms to this bondCurveId
(i.e. NOType
).
In CSMv2 the concept of an "Entry Gate" is proposed to be introduced. Essentially, instead of the create/add node operator methods being permissionless, they are permissioned methods that can be assigned to an allow-listed set of "Gates". These Gates can be thought of as bouncers at a club, which basically check certain things before letting partygoers (NOs, in this case), in. Gates are smart contracts, but the mechanism behind the "identification" and "verification" of NOs enabled by the gate does not have to necessarily be on-chain code (i.e. the Gate could be a contract that processes information from an oracle, or a multisig with people behind it who review applications and associated data, or some sort of (ZK) proof verification mechanism for various proof types, etc.). By making Gates a mechanism "external" to the module core, the same mechanism can be used by other modules in the future, or even other protocols. By assigning the ability to add new Node Operators to the module registry to a Gate, a module can also define which NO types a Gate can create.
In CSMv2, which would be a permissionless module, at deployment there would be at least one Gate, which would work the same way CSM works right now, such that the create node operator method (through the Gate) would be permissionless. As a result, it follows that Node Operators created in this manner should allow for "maximal robustness" of the module (i.e. have the strictest safety and risk assessment treatment of other operator types). Thus, the "default" CSMv2 gate would only be able to create a "default" type of NO, which module mechanics would then be tailored to given the characteristics of such an NO type (fully permissionless, with no Sybil resilience). Another Gate (or set of Gates) that could be added to CSMv2 (even at deployment), would be Gates that serve as (likely) Independent Operators verification mechanism (e.g. some sort of combination of a proof of humanity + past solo staker participation, or something like Gates enabling vouching by groups engaged in solo staker identification (https://www.stakersunion.com/)).
Identifying types doesn't necessarily need to be restricted to whether an Operator is an Independent Operators, or a professional org. It could include other aspects/characteristics of the Node Operator, such as if that NO is a Cluster (group of participants running DVs) (as some modules can't see beyond the "node operator" in the registry which may be a cluster), or if the NO is a participant in a DVT cluster who is identifiable (or not).
For example, if the Gate is able to vet/verify that all participants in a DV Cluster are identified and independent, then it could allow for the module to treat this type of cluster different than a cluster with permissionless elements where verifiability of independence between participants is not possible to ascertain.
Below is a rough list of possible NO characteristics that could be used to define NO Types for different modules
Characteristic | Desc | Values |
---|---|---|
Classification | The general "type" of the Node Operator (e.g. are they are professional business, or a hobbyist, is it a group of people or entities running validators together, is it a service (e.g. VaaS) underlying the NO instead of a person or business entity etc.) | … |
Infrastructure | How the infra for a Node Operator is run (do they run it themselves? do others run (parts of) it for them? where? etc.) | … |
Size | How "big" is the node operator (overall) and/or how big do we anticipate the NO to be in the context of the module | … |
Location | Where is the NO located | … |
Jurisdiction | Are there any regulatory constraints related to the node operator | … |
Identity | Is the operator known (if so, to what degree can it be verified, etc) | … |
Alignment & Ecosystem Impact | Through a mix of qualitative assessments and possibly tangible metrics, it's also possible to assess wider impacts of an NO's presence and activities within the community and wider network. Do they develop public goods? Are they stewards? Do they support credible neutrality of the network? Are their business practices fair and transparent and in line with the values of the community and the wider network? | … |
As a result, through various combinations of the above characteristics, these possible NO Types could be defined (e.g. for use in CSMv2) (note: this list is not exhaustive by any means!).
Type | Sec |
---|---|
Default | Non-identifiable, Sybillable, and permissionless |
Independent Operators | Likely independent operators (via some sort of validating/vetting/verification mechanism) |
Pro | Identified professional node operators |
Pro (undesirable) | Identified professional node operator with a very low alignment & ecosystem impact score |
Validator as a Service | Node Operators underlied by another protocol or Pro NO's VaaS product |
DVT Cluster (permissionless) | Cluster of unidentified participants running validators together |
DVT Cluster (sybil resistant) | Cluster of identified and independent participants running validators together |
DVT Cluster (mono-operator, high resilience) | A single node operator using DVT to run infrastructure in a highly resiliant (e.g. multi-locatino) setup |
Public-good operator | An operator which also provides (or perhaps chiefly provides) public goods for the network |
<Your idea here!> | … |
These are just ideas. Some are easily doable in CSMv2, some are a bigger lift and may be better utilized in another module, or CSMv3, or not at all. Some it makes sense to implement in a simplified manner (e.g. using the strikes system instead of a safety matrix) until the use case is clear for a more complex and robust mechanism.
These Parameters should be defined for a default case per module, and additional any NO Types that the module supports could have overrides for these parameters. Modules could share definitions between themselves, but don't have to.
Parameter | Type | Desc |
---|---|---|
NO Rew. Share | Perk | Share of staking rewards accruing to the Node Operator (related to number of validators they run) |
Num validators | Perk | Number of validators the NO can run (per NO-entry) |
Deposit Priority | Perk | A priority value when determining sorting order in deposit queue |
Exit priority | Perk | A priority value when determining sorting order in request for exits |
Secondary queue | Perk | Whether an NO is eligible for a secondary deposit queue |
Secondary queue limit | Perk | How many total validators an NO can submit via the secondary deposit queue |
Bond curve | Perk | Which bond curve the NO is able to use |
Key Removal charge | Safety Mechanism | What value to charge for key removal from active queue |
Block Stealing charge | Safety Mechanism | What value to charge for block stealing (i.e. incorrectly configured Fee Recipient) |
Safety matrix | Safety Mechanism | Which safety matrix the NO type is subject to. |
Idea is that each NO type can be assigned to a different matrix, where different point thresholds are required for different safety actions (e.g. validator or operator ejection).
eg For for NOType == default
Parameter | Type | Desc | Points |
---|---|---|---|
PointsLifetime | Int | How long (in frames) infraction points "last" for (e.g. if the value is 3 , only points incurred in the current and previous two frames are taken into account). |
N/A |
SubparPerfThreshold | Int | Performance Oracle performance rating threshold under which a validator is considered under-performing (per validator, per frame) | 40 |
InactivePerfThreshold | Int | Performance Oracle performance rating threshold under which a validator is considered inactive (per validator, per frame) | 60 |
ValEjectionThreshold | Int | Points threshold at which a validator is ejected due to bad performance | 70 |
MinValsFullExit | Int | Minimum Number of validators affected relating to SubParperfThreshold or InactivePerfThreshold in order to fully exit a node operator |
2000 |
MinValsFullExit | Int | Minimum Number of validators affected relating to SubParperfThreshold or InactivePerfThreshold in order to fully exit a node operator |
2000 |
UncompensatedMEVPenalty | Int | MEV Penalties an operator can have before full ejection (lifetime) | 2 |
NOEjectionThreshold | Int | Points threshold after which an operator is fully ejected (for relevant points in PointsLifetime ) |
10000 |
e.g. as a result of the above, a validator for NOType == default
is ejected after >= 2 frames of subpar performance (2 * 40 > 70) or 2 frames of ~ inactivity (2 * 60 > 70), but a validator for NOType == independent
could have a different threshold for ValEjectionThreshold
(e.g. ValEjectionThreshold == 110
would allow for 3 consecutive frames of subpar performance.
Parameter | Type | Desc | Strike Count |
---|---|---|---|
StrikeLifetime | Int | How long (in frames) infraction strikes "last" for (e.g. if the value is 3 , only strikes incurred in the previous and current frame are taken into account). |
N/A |
SubparPerfThreshold | Int | Performance Oracle performance rating threshold under which a validator is considered under-performing (per validator, per frame) | 1 |
InactivePerfThreshold | Int | Performance Oracle performance rating threshold under which a validator is considered inactive (per validator, per frame) | 2 |
ValEjectionThreshold | Int | Strike threshold at which a validator is ejected due to bad performance | 3 |
More to come here…
CSM v2 https://hackmd.io/@lido/HJrMPHUt0 CSMv2 Strikes https://hackmd.io/@lido/r1rLoBVXJg
Gate stuff (https://hackmd.io/-2_u2peQRuiumZHE_B0vhA?both#Evolution-of-the-Early-Adoption-Mechanics), Skh working on a dedicated doc
The current list of the params is here https://github.com/lidofinance/community-staking-module/blob/develop/src/CSParametersRegistry.sol