-
Notifications
You must be signed in to change notification settings - Fork 90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd: add combine
command
#1799
cmd: add combine
command
#1799
Conversation
This command accepts an input directory path containing all the private key shares of a DV, an output directory path, and a lockfile path. While the output directory can be nonexistent (will be created automatically), input and lockfile paths must exist. The result of this process is a keystore file containing the combined private key of the distributed validator.
Codecov ReportBase: 54.99% // Head: 55.10% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## main #1799 +/- ##
==========================================
+ Coverage 54.99% 55.10% +0.10%
==========================================
Files 169 170 +1
Lines 22137 22215 +78
==========================================
+ Hits 12175 12242 +67
- Misses 8396 8404 +8
- Partials 1566 1569 +3
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
cmd/combine.go
Outdated
func bindCombineFlags(flags *pflag.FlagSet, inputDir, outputDir, lockfile *string) { | ||
flags.StringVar(inputDir, "keyfile-dir", "./validator-keys", `Directory containing all the "keyfile-N.json" and "keyfile-N.txt" files`) | ||
flags.StringVar(outputDir, "out-dir", "./recombined-validator-key", "Directory where to save the resulting private key") | ||
flags.StringVar(lockfile, "lockfile-path", "./lock.json", "Charon lock.json file") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggest aligning with run
flag: lock-file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this work for e.g. a 10 validator, 4 node cluster? Do you put 40 files in a flat folder? or 4 subfolders? do we do any traversing/exploring subdirectories? Would be great if we could dump e.g. 4 .charon
folders slightly renamed alongside one another, and our command is able by default to find the lockfile(s) and validator_keys
folders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this command should be require some work from the user: to recombine all the keys, it's assumed some work is needed to arrange them in the correct order.
If we want to automate some part of this, we could (as you suggested) let the user provide the validator_keys
directories renamed with the public key share, and do some directory traversing to recombine.
I still believe though that each validator recombination needs a separate invocation of the combine
command.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmmm similar to exits, I believe in practice we will see people mostly combine/exit all validators in a cluster or none. I think partial will be a rare edge case. With the scale of enterprise deployments, I don't think a separate invocation per key is scalable, everyone will DIY their own shell script for-loop.
I think @Battenfield should user test some options, but I think 'people will send their .charon
folder to the combiner, the combiner will dump all n
folders into one directory, having to rename each of them something other than .charon (awkward but feels unavoidable), and from there I think they should be able to run charon combine --data-dir ./this-folder-ive-prepared
, from where we should be able to traverse it, assuming that each subdir is a .charon folder, and we can find ./this-folder-ive-prepared/*/cluster-lock.json
in each of them, along with their enr so we know who is who, and even a ./this-folder-ive-prepared/*/validator_keys/*
path that we can use to find hopefully all of the keystores we expect. Assuming we can find everything we need, get or create output-dir
and spit out the combined keystores. This discovery should probably only need to find threshold number of operators rather than everyone in the lock file (e.g. 3 folders of stuff in a four node cluster, so that you can combine
with the minimum number of participants).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
everyone will DIY their own shell script for-loop
Correct, I implied users will do something similar... I don't see it as being completely unfeasible, and on the flipside depending on deployments needs it could actually be more comfortable.
I imagine a K8S deployment where validator keys are secrets, you have to script your way around the secrets API to mount directories in pods and have combine
work with them anyway.
Regardless, I'm open to changes on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, you make me also wonder should we add a keymanager-address
flag like the DKG and create cluster command, that can push the combined keys into a web3 keymanager. (can make a separate ticket for this, too much scope creep)
I think humour me on this one and we go with this combine
command attempting to combine every private key in the lockfile and warns/(errors and needs to be flag overridden) if it can't discover a threshold of the private keys and passwords it needs to complete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, let's go this way.
An issue that arises is usability.
Users don't know what's in their keystore (what share is represented by a given keystore file?), and even if this is an information that can be easily obtained by opening the JSON file, I'd say not everybody is willing to do so.
A thing we could do is the following:
- each operator creates a directory named after their ENR, and places all the JSON and txt keystore files in it
- one operator collects all the directories and places them in a parent directory, and then invokes the
combine
command pointing it to said directory, the lock file and an output directory - the tool firstly makes sure that there are the same number of directories as the number of operators, and that those directories are named after the ENRs
- for each validator
N
, counting from 0 toNumValidators
,combine
readskeystore-N.{json, txt}
and yields the public key, checking that it's contained in theN
-th validator entry in the lock file - assuming this is correct, it proceeds with the combination and saves the resulting private key in the destination directory, with the JSON and txt files named after the root public key
- runs this for each validator in the lock file
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@corverroos @OisinKyne considering this process yields recombined private keys, I think it's better to write a file with the private key bytes to disk instead of our own keystore files: if a group of operator wants to recombine their private key(s), most probably they want to stop using charon, so writing keystore files seems a bit pointless.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gsora the intention behind writing a keystore is to align with an ethereum standard here https://eips.ethereum.org/EIPS/eip-2335 This is a format supported by all clients. The idea is they would import these keystores into the clients as if they were exported from the eth2-staking-cli. Our .charon/validator_keys
folder also matches that structure (albeit with key shares not 'normal' keys)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I’ll write keystore files then.
The rest of the UX is fine for you?
Co-authored-by: Dhruv Bodani <[email protected]>
# Conflicts: # cmd/run.go
Added function documentation on what it expects in order to work.
Removing the @OisinKyne I added some docs on what the |
commit a04ce78 Author: Dhruv Bodani <[email protected]> Date: Mon Feb 20 20:04:37 2023 +0530 *: upgrade to go1.20.1 (#1824) Upgrades go version to 1.20.1. category: misc ticket: #1821 commit c63199e Author: corver <[email protected]> Date: Mon Feb 20 15:36:34 2023 +0200 gomod: upgrade libp2p (#1823) Upgrades libp2p to v0.25.1 category: refactor ticket: none commit e3161a3 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Feb 20 10:41:34 2023 +0000 build(deps): Bump golang.org/x/net from 0.6.0 to 0.7.0 (#1822) (dependabot) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.6.0 to 0.7.0. commit ce76297 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon Feb 20 10:36:13 2023 +0000 build(deps): Bump github.com/attestantio/go-eth2-client from 0.15.3 to 0.15.4 (#1819) Bumps [github.com/attestantio/go-eth2-client](https://github.com/attestantio/go-eth2-client) from 0.15.3 to 0.15.4. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/attestantio/go-eth2-client/commit/c06075ae2b1cce11556e07dde1ff7b650668b80c"><code>c06075a</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/attestantio/go-eth2-client/issues/46">#46</a> from attestantio/dvt</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/776af407e5ea768d2e534331cf85a7fb3ac59d59"><code>776af40</code></a> Merge branch 'master' into dvt</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/d21be8e84af4a8e953b996de7818e8698e8bdb2d"><code>d21be8e</code></a> Fixes</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/6a22388d146182276771328f6e415c4fa17bb362"><code>6a22388</code></a> Update http/blindedbeaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/c2b26ac084e7227396e33021bd1035b1a9fdb9b2"><code>c2b26ac</code></a> Update http/blindedbeaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/3ca9b6d4dee2ddfb607808cfcd52862be5ad8f2e"><code>3ca9b6d</code></a> Update http/beaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/9646809365152d3eb7c239d0339e4aac91bef58a"><code>9646809</code></a> Update http/beaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/d29581f31c965436f465c034b56c507c5e0f73e9"><code>d29581f</code></a> Update http/beaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/870a2f3a67465c8a7c2476dc284103d0a05a06e0"><code>870a2f3</code></a> Update http/beaconblockproposal.go</li> <li><a href="https://github.com/attestantio/go-eth2-client/commit/097a53c5ef6c46b844c2804693bff3967f99db86"><code>097a53c</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/attestantio/go-eth2-client/issues/45">#45</a> from avalkov/support-extra-headers</li> <li>Additional commits viewable in <a href="https://github.com/attestantio/go-eth2-client/compare/v0.15.3...v0.15.4">compare view</a></li> </ul> </details> <br /> [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/attestantio/go-eth2-client&package-manager=go_modules&previous-version=0.15.3&new-version=0.15.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> commit bf0f469 Author: corver <[email protected]> Date: Fri Feb 17 15:48:09 2023 +0200 dkg: add deposit data to lock file (#1815) Populates the deposit data field in the generated lock files. category: feature ticket: #1775 commit b16fd01 Author: Gianguido Sorà <[email protected]> Date: Thu Feb 16 17:45:18 2023 +0100 p2p: remove pointless "No connections to relay" log line (#1816) That log line wasn't useful anyway. category: refactor ticket: none commit 14d6b7c Author: corver <[email protected]> Date: Thu Feb 16 17:43:32 2023 +0200 cluster: draft v1.6 lock with deposit data (#1813) Adds a new draft lock version v1.6 which includes deposit data in the lock's distributed validators. category: feature ticket: #1775 commit d56cfd5 Author: corver <[email protected]> Date: Wed Feb 15 16:25:55 2023 +0200 cmd: route libp2p to charon logger (#1810) Fixes issue with libp2p using its own logger. Instead, it now logs via the configured charon logger (incl pushing to loki if enabled). category: refactor ticket: none commit f1d260b Author: corver <[email protected]> Date: Wed Feb 15 09:17:04 2023 +0200 app: add a test for remote relay connections (#1808) Adds a test/script to test remote relay connection count. category: test ticket: none commit 3c91888 Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue Feb 14 17:07:50 2023 +0000 build(deps): Bump go.uber.org/goleak from 1.2.0 to 1.2.1 (#1807) (dependabot) Bumps [go.uber.org/goleak](https://github.com/uber-go/goleak) from 1.2.0 to 1.2.1. commit fbfbfdf Author: corver <[email protected]> Date: Tue Feb 14 17:45:11 2023 +0200 cmd/relay: fix connection limits (#1805) Fixes issue with relay limits not being applied correctly getting stuck at 256 connections. category: bug ticket: none commit bc73565 Author: Dhruv Bodani <[email protected]> Date: Tue Feb 14 21:00:09 2023 +0530 compose: fix very large smoke test (#1797) Enables very large smoke test with 7 of 10 cluster and 100 validators. category: test ticket: #1471 commit 2403c2a Author: Abhishek Kumar <[email protected]> Date: Tue Feb 14 16:48:02 2023 +0530 validatorapi: fix content type in http response (#1803) Fixes sending incorrect `Content-Type` header in HTTP response. Found this bug while integrating nimbus VC which errored when charon sent `text/plain` instead of `application/json`. category: bug ticket: none
Co-authored-by: Dhruv Bodani <[email protected]>
@OisinKyne instead of creating a single I implemented what you suggested wrt the input directory tree (aka it's compatible with Is that fine? |
# Conflicts: # go.mod # go.sum # p2p/relay.go
Have you tried importing private keys in that format into validator clients? I don't believe that structure would be recognised. See: I think only one Second thing I want to check is that the format |
Oh I see! Ok, I'll move the json and txt file down under a validator_keys directory, then I'd say we're good to go with the merge. |
cmd/combine.go
Outdated
} | ||
|
||
func bindCombineFlags(flags *pflag.FlagSet, keystoresDir *string, force *bool) { | ||
flags.StringVar(keystoresDir, "keystores-dir", "./", `Directory containing all the keystore files organized by ENR, and the lock file.`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
flags.StringVar(keystoresDir, "keystores-dir", "./", `Directory containing all the keystore files organized by ENR, and the lock file.`) | |
flags.StringVar(keystoresDir, "cluster-dir", ".charon/cluster/", `Parent directory containing a number of .charon subdirectories from each node in the cluster.`) |
--cluster-dir
aligns with charon create cluster
, see no keystores-dir
in our code yet.
Not sure about the default folder, maybe it could be ./obol/
, will post something in #dev or see if chris has a strong product opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would push for ./.charon
to keep it aligned with all the other cli commands.
} | ||
|
||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't looked at the encompassing error handling around this function, but can a partial success happen where we don't manage to combine all keys successfully but do output some? We probably don't want to allow that, and should fail entirely if that's not already the case. (assume we freak out if err != nil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, the function will error out if one of the validator keys can't be combined but the artifacts of the other keys will remain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm merging this PR, let's address this behavior in a separate one if needs a change.
return cluster.Lock{}, nil, errors.Wrap(err, "cluster lock hash verification failed") | ||
} | ||
|
||
if err := lock.VerifySignatures(); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we allow --no-verify
flags on this command @corverroos ? Imagined use case would be trying to recombine a really old cluster in a modern (>v1.0) charon version, and not being able to get it to verifySignatures correctly? (Or we can just pinky promise to always support old signatures/verification for anything that could possibly be in prod?)
Happy to skip this if not a concern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm merging this PR, let's address this behavior in a separate one if needs a change.
Co-authored-by: Oisín Kyne <[email protected]>
Co-authored-by: Oisín Kyne <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want a slight change to the output format, a couple of tweaks to the explainer text.
For now, I've suggested a different default folder path, I don't like what I've suggested as .charon/cluster
, but that is where the default create goes, so I think we should put the default combine there too, and fix both shortly together.
This commit adds the
combine
command.It accepts an input directory path containing all the private key shares of a DV, an output directory path, and a lockfile path.
While the output directory can be nonexistent (will be created automatically), input and lockfile paths must exist.
The result of this process is a keystore file containing the combined private key of the distributed validator.
category: feature
ticket: #1311