ethereum / consensus-specs

Ethereum Proof-of-Stake Consensus Specifications
Creative Commons Zero v1.0 Universal
3.55k stars 968 forks source link

Dual-key voluntary exits #1578

Closed JustinDrake closed 11 months ago

JustinDrake commented 4 years ago

Currently voluntary exits are signed by the validator's hot key to avoid validators having to access cold storage. In the context of a staking service owning the hot key and a staking customer owning the cold key, it may make sense for validator exits to be signable by either the hot or cold key to always allow the staking customer to exit the staking service (e.g. if the staking service goes offline).

ghost commented 4 years ago

This is more than a nice to have feature, as it allows staking-as-a service platforms to offer a clearer use case to their customers. Thank you, @JustinDrake for proposing this enhancement.

mcdee commented 4 years ago

It is already possible for a staking service to provide a signed VoluntaryExit transaction to their customers. This isn't quite the same, in that the transaction becomes invalid after a couple of forks, but it has the benefit of not requiring any spec changes.

This would also make #1543 irrelevant, which would lose a second chance system where the validator service could work with the staker to retrieve funds safely even if the withdrawal key is exposed.

djrtwo commented 4 years ago

As discussed with @vbuterin:

There is another argument for signing exits with the active signing. In the long term, withdrawal credentials will be a piece of code, or even a pointer to an EE and a message, not a key. So you can't generically "sign with" the withdrawal credentials, as it is just instructions for where to send the money when you're done.

ghost commented 4 years ago

Thank you very much you for your response @djrtwo

withdrawal credentials will be a piece of code, or even a pointer to an EE and a message

In that case, I would propose to consider the option to wrap into such message the public aspect of a cold key, to give staking services the alternative for customers to trigger their voluntary exit.

vbuterin commented 4 years ago

Another option would be for the hot key to just pre-sign a VoluntaryExit message.

JustinDrake commented 4 years ago

Another option would be for the hot key to just pre-sign a VoluntaryExit message.

@mcdee pointed out that the pre-signed messages can become invalid after forks.

mcdee commented 4 years ago

Two forks, to be fair, which should give holders of the hot key time to sign another message. Not great if you've buried your withdrawal keys and pre-signed messages in concrete somewhere, but probably something that could be overcome in the majority of cases.

(I did discuss the idea of using fork-independent signatures for voluntary exits; I believe there was an issue with doing this but I'll admit I can't remember the details.)

djrtwo commented 4 years ago

just pre-sign a VoluntaryExit message.

VoluntaryExits have an epoch to prevent being played early or maliciously picked up and replayed on a fork much earlier than intended. A pre-signed would have to have an early epoch and be at risk to potential misuse

sgryphon commented 4 years ago

Is there any problem with the staking service simply giving a copy of the hot key to their customer, to store alongside the customer's cold key? The cold key is that one that needs to be kept safe; keeping the hot key also offline doesn't add any security issues. Really, both keys should be owned by the actual customer, with the hot key only being giving to the service so that they can act on behalf of the customer.

Another thing, if it is relevant, is checking the specs:

So, while there could be multiple withdrawal keys on Eth 1 (e.g. two people share half the cost each), only one of them (the first) is recorded in Eth 2. I am not sure if this is intentional.

Even if it was intentional (i.e. we go back to the deposit data for each part of the withdrawal), with multiple stakers backing one validator, the situation between half dual-key exit, pre-signed exit, and simply giving the customer the hot key is pretty much the same:

Either the customer owns the full amount, so should have full access to the hot key; or it is shared between customers, and none of them should have access to unilaterally exit (certainly not the one who just happened to be first).

mcdee commented 4 years ago

Is there any problem with the staking service simply giving a copy of the hot key to their customer

It would open up the validator to being slashed, which neither party would want. A sane staking service would treat their validator keys with as much, if not more, care then the staker would their withdrawal keys.

dankrad commented 4 years ago

It would open up the validator to being slashed, which neither party would want. A sane staking service would treat their validator keys with as much, if not more, care then the staker would their withdrawal keys.

The ideal way to keep the key is in a HSM that only allows certain operations, and exporting the key is not one of them. However, there does need to be a backup of this key anyway (e.g. in case of physical destruction of the HSM), so what could be done is to export the hot key encrypted using the withdrawal key at signup. At that point, the staking service would be creating some form of cold storage backup of the key anyway, so I don't think that it actually worsens security.

mcdee commented 4 years ago

Not sure why you would want to encrypt the validator key with the withdrawal key, given the withdrawal key is out of your control. For a large staking services that may mean getting in touch with hundreds of users and asking them to decrypt something for you if you ever lose your HSM.

(Backup of validator key is of course important, but not sure I'd want to do it this way.)

(And totally derailing the issue now, any news on reasonable HSMs that support BLS12-381? Is SGX or similar TEE the way forward for now?)

dankrad commented 4 years ago

Not sure why you would want to encrypt the validator key with the withdrawal key, given the withdrawal key is out of your control.

Because the withdrawal key owner is the actual owner of the stake, so they should ultimately control it if they want to

For a large staking services that may mean getting in touch with hundreds of users and asking them to decrypt something for you if you ever lose your HSM.

I'm not suggesting this as the only backup, but as an additional one, that should add almost no risk if executed properly (as the withdrawal key should be in cold storage anyway).

mcdee commented 4 years ago

Because the withdrawal key owner is the actual owner of the stake, so they should ultimately control it if they want to

Although I get the philosophy I don't think the practicalities (and legalities) would allow this. Allowing multiple entities to have access to the validator key would make the waters incredibly muddy if a slashing event ever occurred, as to who caused what.

Magicking commented 4 years ago

From the standpoint of a staking service, I would as much as possible not have a key I hold&use with a hardened system(HSM) be in the hand of an end-user or third-party service, that would go against securing SLA for the said end-user client.

From the standpoint of a user, I would as much as possible prevent a third-party from behaving suboptimally (i.e: not meeting SLA) and I would most probably use another third-party service to ensure that the staking service provider I registered to doesn't go wild.

As of now, there is 3 possible actions (attest/voluntarily exit/withdraw) with only 2 types of keys (validator/withdraw), so from the user standpoint, in order to voluntarily exit:

This proposal is about assigning the role voluntarily exit to the withdrawal key, this is a halfway solution to role assignment to keys but a better solution nonetheless as it gives more power to the user!

Side note: In the scenario above where you have 2 services and 1 user, the ideal solution is to have 3 keys with different role except for the key kept in cold storage (withdrawal key) that could/should have more power and a way to rotate/update key specified in the deposit contract. Since we have few roles, they could be stored in a bitfield along with the pubkeys / key commitments.

djrtwo commented 4 years ago

Another option would be for the hot key to just pre-sign a VoluntaryExit message.

This was discussed on the latest eth2 call (a week and a half ago) and had general support, including from @hermanjunge.

I want to gauge sentiment on that path. Any further comments here?

ghost commented 4 years ago

Any further comments here?

Only that we need to add a digest of this rationale path somewhere at the annotated specs project.

Relevant bits

dankrad commented 4 years ago

So thinking about this I still think it's a good idea to allow this. The main argument against it seems to be that "at some point in the future the withdrawal key won't be a key but may be a contract address".

That's true, however, I do think that the contract should also be able to initiate withdrawal:

I think we should go further and (in the future) allow the withdrawal key/contract to change the staking key. This will mean that loss of the staking key is not an unacceptable loss anymore, and we can for example use simple hardware modules that don't allow any export (not even backup) -- this might mitigate many of the concerns of people being able to hack/acquire lots of keys.

darcius commented 4 years ago

Allowing a contract to initiate withdrawals would simplify our withdrawal process at Rocket Pool a lot and really allow the users to be in full control. Currently we're looking at using a custom p2p package which makes an aggregate key from several decentralised nodes, but we could remove this completely if a smart contract could initiate a withdrawal (less moving parts the better).

We'd very much be in favor of that :)

mcdee commented 4 years ago

Although I like the idea of the additional functionality, I think this is starting to overload the function of the withdrawal key; it's moving away from the idea of being the "lock it away and keep it safe" key to some sort of general-purpose operator key.

Perhaps the answer here is to add a "stake operator" key or similar, so that admin functions can be separated from moving funds?

dankrad commented 4 years ago

Although I like the idea of the additional functionality, I think this is starting to overload the function of the withdrawal key; it's moving away from the idea of being the "lock it away and keep it safe" key to some sort of general-purpose operator key.

I don't quite see it this way -- it is still a key that will only be needed in very exceptional circumstances (loss of staking key, staking operator starts misbehaving, etc. I think with all these proposals it is still perfectly valid to lock this away in a bank safe that you can only access on weekdays.

A smart contract implementation can then easily separate the roles however you like in the future -- allowing to change the staking key with one set of operators and to withdraw with a different one.

ghost commented 4 years ago

Although I like the idea of the additional functionality, I think this is starting to overload the function of the withdrawal key; it's moving away from the idea of being the "lock it away and keep it safe" key to some sort of general-purpose operator key.

I don't quite see it this way -- it is still a key that will only be needed in very exceptional circumstances

Indeed. This would be more like an emergency stop button, to be used once per stake. I do not see how far we are going from the "lock it away and keep it safe" functionality by adding this feature.

The customer would only get his hands into the key in case something really wrong happens with the staking service. It is not in the latter's interest to fail, so adding this feature to the protocol is all about fulfilling UX requirements, impacting positively in adoption.

mcdee commented 4 years ago

Indeed. This would be more like an emergency stop button, to be used once per stake. I do not see how far we are going from the "lock it away and keep it safe" functionality by adding this feature.

My comment was more to the suggestion by @dankrad :

I think we should go further and (in the future) allow the withdrawal key/contract to change the staking key.

which would not be a "stop" action, only ever sent once in an emergency. If we want this type of functionality we may be better off considering the roles and requirements all in one go rather than adding feature creep to keys where they shouldn't, just because we only have two keys with which to work.

dankrad commented 4 years ago

which would not be a "stop" action, only ever sent once in an emergency. If we want this type of functionality we may be better off considering the roles and requirements all in one go rather than adding feature creep to keys where they shouldn't, just because we only have two keys with which to work.

I disagree, I still see this as an emergency action meaning "I've lost my key" or "My staking provider has gone offline". It's technically just shortcut to exiting and restaking, which comes with long capital lockup times, which are actually unnecessary given that the same amount of capital will be staked again (and is, of course, still subject to slashing by messages from the previous staking key(s)).

mcdee commented 4 years ago

I still see this as an emergency action meaning "I've lost my key" or "My staking provider has gone offline".

The point was that it isn't a "one and done": after the operation has taken place the key is still required.

(and is, of course, still subject to slashing by messages from the previous staking key(s))

That would, as far as I'm aware, require a pretty big change to the spec.

To reiterate: I'm all for having a friendlier system for staking, but worry that without working from a set of requirements to a proposed solution we'll end up with a confusion of keys and purposes. Would you be interested in working with me on a doc outlining such requirements/features as a first step?

JustinDrake commented 4 years ago

What's the consensus on this proposal? (Feel free to react to this comment with the 👍or 👎 emoji to signal where you stand—👍to support dual-key exits, 👎otherwise.)

mcdee commented 4 years ago

Could we have a "worry about after phase 0 releases" option? There are various items that would make stakers' lives easier, but I don't see them going in before phase 0 has shipped.

JustinDrake commented 4 years ago

There are various items that would make stakers' lives easier

A meta-issue that lists all the items would be fantastic :)

mcdee commented 4 years ago

Happy to create one, if you're happy with me opening a new issue whilst you're so hard at work closing existing ones down :)

JustinDrake commented 4 years ago

if you're happy with me opening a new issue

More than happy with fresh constructive issues :) It's the stale not-super-constructive issues that I try to close 😂

dankrad commented 4 years ago

I'd still claim the current state is crazy and dangerous. We will absolutely need a replacement at some point!

tzapu commented 4 years ago

i’ve seen on discord that this might be going in soon. could someone maybe clarify here what the plans currently are? thank you very much

dankrad commented 4 years ago

I feel like there is a consensus that something like this should happen in phase 1 :)

coltonc3 commented 3 years ago

Relevant bits

  • A staking service may provide a VoluntaryExit pre-signed message to a customer.
  • A 3rd party mechanism may be implemented to scan the validity of a message of the former kind, as certain conditions (such as forks) could render it invalid.

From the perspective of a staking service, could anybody please shed light on what the pre-signed message would entail? Parameters and format? Thank you in advance.

mcdee commented 3 years ago

The message would be a https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#signedvoluntaryexit

Format would be implementation-dependent.

sergeyWh1te commented 2 years ago

Hi! After almost one year, I want to continue a discussion about voluntary exit from staking-service side.

Right now we have several designs how to achieve this:

1) Custom Third Party application using pre signed messages. 2) Modify ETH spec for ability, adding code for voluntary exit on contract side. It seems that super hard task. 3) Using standard validators software like dirk or prysm. What do I mean?

I made a research where I found that's possible to pre sign exit messages though grpc. Let's take for example dirk

It has two grpc endpints: /v1.Signer/Sign,
/v1.Signer/Multisign


 type SignRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    // Types that are assignable to Id:
    //  *SignRequest_PublicKey
    //  *SignRequest_Account
    Id     isSignRequest_Id `protobuf_oneof:"id"`
    Data   []byte           `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
    Domain []byte           `protobuf:"bytes,4,opt,name=domain,proto3" json:"domain,omitempty"`
}

type MultisignRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Requests []*SignRequest `protobuf:"bytes,1,rep,name=requests,proto3" json:"requests,omitempty"`

type SignResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    State     ResponseState `protobuf:"varint,1,opt,name=state,proto3,enum=v1.ResponseState" json:"state,omitempty"`
    Signature []byte        `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
}

type MultisignResponse struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    Responses []*SignResponse `protobuf:"bytes,1,rep,name=responses,proto3" json:"responses,omitempty"`
}

But, for calling them, you have to provide a client certificate. It means that I like node operator has to add new one certificate and restart dirk instance, right? @mcdee Please, provide my thoughts.

Also, same possibilities I found in prysm

Grpc endpoint - /ethereum.validator.accounts.v2.Accounts/VoluntaryExit

type VoluntaryExitRequest struct {
    state         protoimpl.MessageState
    sizeCache     protoimpl.SizeCache
    unknownFields protoimpl.UnknownFields

    PublicKeys [][]byte `protobuf:"bytes,1,rep,name=public_keys,json=publicKeys,proto3" json:"public_keys,omitempty"`
}

type VoluntaryExitResponse struct {
   state         protoimpl.MessageState
   sizeCache     protoimpl.SizeCache
   unknownFields protoimpl.UnknownFields

   ExitedKeys [][]byte `protobuf:"bytes,1,rep,name=exited_keys,json=exitedKeys,proto3" json:"exited_keys,omitempty"`
}

Like in dirk, I like a node operator has to add new one certificates for calling this method. After calling grpc methods I'll receive signatures of presigned messages for voluntary exits without real exiting. And then using those signatures, i can call https://ethereum.github.io/beacon-APIs/#/Beacon/submitPoolVoluntaryExit somewhere in third party daemons.

mcdee commented 2 years ago

Signing a voluntary exit operation is separate from broadcasting it to the network, and can be obtained using various methods today (for example ethdo). ethdo can also submit a pre-signed exit transaction to a beacon node.

sergeyWh1te commented 2 years ago

Signing a voluntary exit operation is separate from broadcasting it to the network, and can be obtained using various methods today (for example ethdo). ethdo can also submit a pre-signed exit transaction to a beacon node.

My aim is obtaining pre signed voluntary messages and I found that it's possible like in my previous post. Also, I hoped on your opinion, is it ok or not.

mcdee commented 2 years ago

Yes, many staking service providers already have this service. To be clear, if you are set up with ethdo (with any backend, be it dirk or local keys) you can simply run:

ethdo validator exit --json --account=MyWallet/MyAccount --passphrase=secret

and it will produce the pre-signed exit transaction.

sergeyWh1te commented 2 years ago

First of all - thank you for your answers. You really help a lot.

or local keys) you can simply run: This's totally OK then person runs one or two validators.[JUST call cli command from dirk/prysm/teku and etc].

But what to do for example if somebody runs 100+ different validators clients. Such as 30 -prysm, 30 -teku, 30 dirk and etc, I hope I described the situation. It's too hard to go to each one validator client and switch it off.

Instead of that approach I try to find a way how to automatize this task. After reading a lot of code I found that some of them like dirk, prysm have grpc services inside themselves. Those allows me write something common for interacting with validators services.

To according your message above, i got that you're ok with it. Right?

mcdee commented 2 years ago

People running large numbers of validators are likely to protect their keys using the more advanced systems such as dirk, web3signer, etc that provide the ability to generate signature for voluntary exits.

VVander commented 1 year ago

As discussed here, removing the fork number validity limitation on withdrawal messages (similar to deposits) would help staking protocols significantly while being a very small spec change. Seems like a great interim step while work on deeper EL/CL communication is ongoing.

I've never contributed to the spec before, but if there's enough consensus on this, I'm happy to do the work for a PR here since it benefits my project immensely.

hwwhww commented 11 months ago

closing via EIP-7002.