On-Chain pDAO Replacement

This topic has been bouncing around our Discord and Twitter for a week or so and appears to have strong community support. If you support the direction, have opposition to it or have any questions, here is the place you can be formally heard. We will develop an RPIP and a formal vote out of any discussions here.

A detailed explanation of the idea can be found here.

I won’t repeat the technical details as you can read the above document. But in summary, the on-chain pDAO replacement will replicate our existing pDAO governance system on chain; importantly, removing the team as an executive middle man and making the entire system completely decentralised.

There are many benefits to this approach but the primary drawback is the increase in gas and complexity. That gas increase comes at a minor cost to node operators and the complexity excludes us from using existing governance software.

The dev team feels like this trade off is worth it, given the alternative is to adopt a simpler voting power model which we feel strongly is not the right direction for the protocol. Rocket Pool’s unique governance system is distinct from other DAOs, making governance capture significantly more difficult and giving power to those most aligned with the protocol’s long-term health in mind.

Please offer any criticisms, ideas or ask any questions you have here.

You can signal support or opposition here as a temperature check, but a formal process will follow.

  • I support the described on-chain pDAO model
  • I oppose this approach (please describe why in a comment)

0 voters

3 Likes

NOTE: There is current discussion to remove the sqrt from the voting power calculation to make it linear. This will not have any major effect on the technical implementation.

For reference, readers may be interested in this initial analysis by @Valdorff and @epineph: Proposal: switch to linear voting power to resist attackers - #10 by Valdorff.

4 Likes

@kane can you give some idea of the gas costs? Both to vote and the bump on the various transactions?

There’s a lot of factors and it’s difficult to give a very accurate value until it’s implemented properly (have only done proof of concept at this time). But ballpark, each of the actions mentioned will require one extra cold SSTORE which is around 22k gas. And as an educated guess, voting will likely be somewhere in the 50-100k gas area. So at 20 gwei gas, somewhere around 0.001-0.002 ETH for a vote.

3 Likes

Looks like a sensible design. Thanks for the research, Kane!

This design, like any on-chain voting mechanism that directly implements proposals, would be vulnerable to vote manipulation (see the infamous Beanstalk hack), so we’ll need to be very sure this kind of attack isn’t possible. I’m sure the auditors will have this in mind, though. Looking forward to seeing the implementation!

This this might be a good opportunity to add some of the extra security features that have been suggested. E.g. time-weighted voting power from my original draft of RPIP-4 and @epineph’s suggestions in this post.

1 Like

I have posted a draft RPIP for consideration: Draft RPIP for On-Chain PDAO by kanewallmann · Pull Request #71 · rocket-pool/RPIPs · GitHub

4 Likes

A node operator MUST NOT be able to withdraw RPL if their staked RPL minus locked RPL is lower than the maximum collateral threshold (currently 150%).

If it’s worded that way and in the future we leave the maximum threshold but specify that you can withdraw at e.g. 50% (without locked RPL), we will have drama all over again, if this now means that this RPIP stays at 150% (for when RPL is locked) or if it intented to match with the withdrawal threshold for when no RPL is locked.

Basically, this discussion about RPIP-4 has made it so much harder to write clear RPIPs :frowning:

I don’t see any problem. Worst case means if we want to change when you can withdraw, we may need to clarify language in an extra RPIP. The rpip-4 thing is rather unique cuz it’s a bootstrap issue.

But I agree we might be able to say some version of “locked RPL counts towards withdrawal thresholds” that will be more robust to future tweaks

3 Likes

Reviewed a bit more than half for the moment. Looks good generally. Biggest high level thing is separating spec from implementation (a takeaway from current RPIP-4 tribulations).

Update 2023-09-11: reviewed the rest. One non-negligible design suggestion in there.

Thanks :pray:

2 Likes

I’m aware that it’s not directly related to the pDAO functionality, but I would like to make an argument for a proper time-lock, especially now that more on-chain functionality is being made available to token holders.

Before some jump in saying: ‘there already is a timelock’, respectfully, I don’t believe there is, unless I’ve completely overlooked it. There is a proposal delay but not a timelock.

I’d define the difference like so: the proposal delay prevents voting on a proposal before the delay expires, this delay comes between on-chain proposal and on-chain voting. A traditional timelock comes into effect post on-chain vote, but prior to on-chain execution.

I think the problem with a proposal delay as opposed to a timelock is that it makes things very awkward for users if there is a malicious proposal.

I’m aware that as per the proposed spec, a bond is required when proposing, so there is a cost to malicious proposals. Still, depending on the potential impact and bond setting, this may still be worthwhile to a griefer, or someone with enough RPL to pass a malicious proposal.

At the time a malicious proposal is waiting out the enforced delay, users of the protocol do not know whether they should react by exiting, because they don’t know yet if the malicious proposal will be voted down. Unless I’m misunderstanding the system, this gives them two options:

  • Exit now, just in case the malicious proposal passes.
  • Wait-and-see, it probably won’t pass after all.

I think both options can have a serious cost to the protocol users (node operators, potentially rETH holders, but I’m unsure if the pDAO can directly impact rETH holders significantly).

EITHER you burn some gas and time exiting in a panic, only for (most likely) nothing bad to happen.

OR you don’t exit, and just kind of hope that the proposer does not have the voting power to pass the proposal in the last block, and immediately execute the proposal in the subsequent block. If this does happen, it may be too late to exit.

It’s maybe worth noting that I believe this dynamic can play out for the oDAO proposals as well, but given the oDAO are considered trusted actors, this falls under: ‘we trust the oDAO, so this is not a problem.’


If I’ve misunderstood anything here, I’m happy to be corrected. Still getting up to speed some here.

3 Likes

Just thinking about this a little and I think we might be able to have our cake and eat it too here. Could have a very short timelock (eg, 3 days) and then let the security council extend that to a specified longer time (eg, 3 weeks). They could do this if a vote was highly contentious, or if there was a last-minute change in votes, eg.

The draft RPIP can be found here:

2 Likes

Some comments and questions regarding the draft:

  1. I suppose the lower (10%) bound should now be removed in the voting power function based on the RPIP-4 clarification vote we just had.
    E.g. have R_{n} = min(S_{n}, M_{n})

  2. If the sum of voting power of votes exceeds the quorum threshold […], the proposal SHALL be executed and its changes affected.

This part is a bit unclear to me. It could be interpreted as if the smart contract executes the proposal as soon as the quorum is reached. Or the proposer could execute it as soon as the threshold is reached. Is this the intention?

There are a couple of related parameters in the Parameter Table (proposal.vote.time and proposal.execute.time), but they are not mentioned in the Specification itself. I think these parameters should be clarified in the spec as to how they are used in the voting and execution of the proposals.

  1. Each node operator who has a non-zero voting power MAY vote […]

Non-zero voting power at the time of the vote or the block the proposal was submitted for? Based on the text below (Snapshotting and Rationale) it can be inferred it’s the latter, and the explanation in rocketpool-research confirms this. But maybe we should clarify the wording in this paragraph as well? (or maybe it’s completely clear to everyone idk)

EDIT: Is it even possible to have a node with zero voting power now, anyway?

  1. Any node with a non-zero voting power MAY raise a proposal at any time provided they have waited longer than the proposal cooldown period since their last proposal.

What’s the cooldown period specifically? Should that be a parameter in rocketDAOProtocolSettingsProposals?

  1. For some reason the rpips.rocketpool.net site does not render the % sign in the voting power function formula (tried different browsers too), while on github the percentage sign is shown. We should probably either fix the issue on the website, or we could write the formula as “× 1.5” instead of “× 150%”.

  2. It would seem there is no way to overrule a delegate’s vote under the proposed system. Are we pushing this out of the scope of the initial implementation?

Any node with a non-zero voting power MAY raise a proposal at any time provided they have waited longer than the proposal cooldown period since their last proposal. RPL equal to the proposal bond SHALL be locked for the duration of the proposal process. In order to be eligible to propose, node MUST have an effective RPL stake (minus any already locked RPL) greater than the proposal bond. Locked RPL SHALL act the same way as regular staked RPL for the purposes of rewards, voting and collateral requirements. Locked RPL SHALL NOT be counted towards thresholds for withdrawing RPL.

What is the reasoning for the bolded part, specifically the reference to effective RPL stake (I’m assuming this means at least 10% and less than 150% here). If a node operator is below the 10% treshold, but has enough RPL staked to cover the proposal bond, why are they excluded? If a NO doesn’t have enough effective RPL staked, but does have enough RPL staked, why can’t they propose?

Same question for requiring effective RPL stake for challengers.

1 Like

I tend to agree with knoshua here that this requirement isn’t necessary. I do think “have nonzero vote power” or “have an active minipool” would be reasonable to propose (but shouldn’t be needed to challenge, as we want the lowest possible barrier to entry to participants on that imo).

1 Like

What is the purpose of submitting delegations as part of the merkle tree for calculating total vote power? As far as I can tell, we only care about total vote power to calculate quorum and delegations do not change the sum. Wouldn’t it be simpler to just calculate sum of vote power regardless of delegations?

I had a go at fixing this on the portal, I couldn’t find a reason (in the half-hour I spent) for it requiring single slash escape rather than double slash escape (github requires the opposite). I would agree that it might be better to just use 1.5.

I did manage to fix the inline latex not working though. [PR]

Edit: I couldn’t let the stupid percent thing go, so I found a hacky fix that makes it work. Don’t love it, not sure if it’ll get merged in. [PR] if anyone is interested.

2 Likes

That’s correct. The design/RPIP was written before the RPIP-4 vote. We will update.

This area has changed a little due to some feedback already given. There will now be two voting periods: one for delegates, one for voters (so they can override their delegate). Once the proposal has gone through both voting periods, the result will be known: success, defeated, etc. If it is successful then the proposal can be executed by either the proposer or a any good samaritan who wants to pay the gas.

We will update the RPIP / design based on this information. We have a timeline and state diagram to help explain.

Yes it will be the block included in the proposal submission - the one that the voting power has been calculated for. The design was written before the RPIP-4 vote - we will update. A node can have zero voting power if they have no minipools.

Great question - the cooldown was originally a security feature but after review we determined it is not necessary, so we have removed it. I believe it was for spam protection but the bond and veto process solves this issue. We will update the RPIP to reflect.

Looks like @LongForWisdom has tenaciously updated.

Based on feedback, we have included a way to overrule a delegate’s vote in the scope.

1 Like

Good pickup. We agree it should not be effective RPL stake here.

To be honest, there isn’t a technical reason why proposers and challengers should be staking. We had the idea that those engaged in these governance activities should be active stakers but it does make it simpler from a code and operational aspect to not have that constraint

The only issue I see, is that it makes it marginally easier to launch a potential attack because they just have to stake RPL, rather than setup a minipool, but we do not rely on the minipool for security, we use the RPL bond so it makes little difference.

We will update to use RPL stake rather than effective RPL stake.

We calculate the total vote power off-chain because we cannot sum the vote power on-chain. We have the same issue for delegates - we need to sum their delegated vote power. So we do it off-chain and include it in the tree. The delegates then submit a proof to their vote power when they vote.