Skip to main content

Creation of distributed validators

info

This page contains a written version of the talk titled "The magic behind trustless distributed validators in Diva," given by Miguel Prada at DappCon 2023.

You can also watch the recording of the full talk here.

The primary purpose of the Diva Smart Contract (DSC) is to accumulate ETH deposited into the Diva Pool by the Stakers and orchestrate the creation of distributed validators. Since a validator in Ethereum requires a minimum of 32 ETH to become active, the deposited ETH need to be grouped in bundles of 32 ETH before creating a new validator. Every time the DSC receives some ETH, if the pool accumulates a multiple of 32 ETH, the DSC will use the RANDAO\mathtt{RANDAO} value to generate one random seed per each 32 ETH bundle [Figure 1].

random-seeds

Figure 1: Each allocation of 32 ETH is assigned to a random seed.

The random seed produced by the RANDAO\mathtt{RANDAO} is considered as Seed0Seed_{0}, and it won’t be used to create a distributed validator. Instead, one sub-seed ValidatorIDxValidatorID_{x} is generated for each distributed validator xx as:

ValidatorIDx=HASH(Seed0)ValidatorIDx+1=HASH(ValidatorIDx)ValidatorID_{x} = \mathtt{HASH}(Seed_{0}) \\ ValidatorID_{x+1} = \mathtt{HASH}(ValidatorID_{x})

Where HASH\mathtt{HASH} is an instance of keccak256\mathtt{keccak256}. The unique identifier representing the creation of a new distributed validator in the smart contract is determined by ValidatorIDxValidatorID_{x}.

As described in [Figure 1], each Diva Node (node) is constantly monitoring the events coming from the DSC, among other things, for the creation of new distributed validators. Diva Nodes are managed by Diva Operators (operators) who deposit collateral and collect part of the rewards generated by the protocol.

One operator can manage multiple nodes, but the creation of new distributed validators is calculated using the operator's identity (thus, it doesn’t depend on the number of nodes the operator has or the identities of those nodes). Any node from an operator can participate in a Distributed Key Generation (DKG) ceremony on behalf of its operator’s identity with a given group of randomly selected nodes. Additionally, operators can enable or disable their nodes as potential DKG participants, allowing for a better load balancing between the nodes fully managed by the operator.

To create a new distributed validator, nodes should be divided into 2 groups (see Participating Entities): participants and coordinators. To create an optimal set of DKG participants, all the nodes that want to participate in the DKG will submit a DKG request to the P2P topic ValidatorIDxValidatorID_{x}. DKG coordinators will pick a set of unique participants that minimizes the value of WeightmintotalWeight_{min}^{total} defined as:

Weightmintotal==min(βˆ‘{Weightparticipanti,Weightparticipantj,...Weightparticipantk})βˆ€Β i,j,kΒ /Β iβ‰ jβ‰ kWeight_{min}^{total} = \\ = min ( \sum\{Weight_{participant_i},Weight_{participant_j},...Weight_{participant_k}\} ) \\ \forall \ i,j,k \ / \ i \ne j \ne k

It's worth noting that participants can have more than one weight value depending on the amount of collateral and, therefore, the number of free key shares that they own (it's equivalent to buying lottery tickets: you can purchase many to increase your chances of winning, but you can only win once per lottery). These weights are calculated for each participant from their operator identity (ii) a key share derivator index (kjk_{j}). After that, a common SeedxparticipantsSeed_{x}^{participants} per validator xx is applied to calculate a unique weight per key share, operator and validator. The weights are then masked with MASKweightMASK_{weight} and converted to uint128\mathtt{uint128} as follows:

Seedxparticipants=HASH(ValidatorIDx,1)Seed_{x}^{participants} =\mathtt{HASH} (ValidatorID_{x},1) Wij=HASH(operatori,kj)W_{ij}=\mathtt{HASH}(operator_{i},k_{j}) Weightparticipantikeysharej=uint128[HASH(Seedxparticipants,Wij)∧MASKweight]Weight_{participant_i}^{keyshare_j} = \mathtt{uint128}[\mathtt{HASH} (Seed_{x}^{participants}, W_{ij}) \wedge MASK_{weight}]

where

SetΒ ofΒ participants={operatori,operatorj,...,operatork}Set\ of\ participants = \{operator_i, operator_j, ..., operator_k\} kj={0,1,2,...,Kfreeβˆ’1}:Kfree=NumberΒ ofΒ freeΒ keyΒ sharesΒ ofΒ anΒ operatork_{j}= \{ 0, 1, 2, ..., K_{free}-1 \} : K_{free} = Number\ of\ free\ key\ shares\ of\ an\ operator MASKweight=0x00000000000000000000000000000000000fffffffffffffffffffffffffffffMASK_{weight} = \mathtt{0x00000000000000000000000000000000000fffffffffffffffffffffffffffff}

On the other hand, all DKG coordinators will calculate which coordinators are optimal (defined as the coordinators with the highest WeightparticipantiWeight_{participant_i}) for coordinating a DKG proposal for ValidatorIDxValidatorID_{x}. Since each coordinator knows its weight and all the other weights, it will know if it was chosen as one of the optimal coordinators and, therefore, should receive participation requests from the participants instead of becoming a participant of the DKG.

The initial timeframe (TF1) for submitting DKG proposals starts at the moment of generation of the validator seed event, ValidatorIDxValidatorID_{x}. Each timeframe lasts 32 blocks, and the coordinator that computes a valid DKG proposal with the lowest set of DKG participant weights will distribute the result via P2P to create the distributed validator during the following timeframe (TF2). If more than one coordinator distributes an identical set of DKG participant weights, the submitter (the entity entitled to submit a transaction with the result of the DKG) will pick one of them arbitrarily. Otherwise, the submitter will select the best DKG proposal among the shared ones over the P2P network.