-
Notifications
You must be signed in to change notification settings - Fork 81
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
Improve KeyManager API import operation #968
Conversation
-- process new validator in parallel instead of serial stream
...ech/pegasys/web3signer/core/service/http/handlers/keymanager/imports/ImportKeystoreData.java
Fixed
Show fixed
Hide fixed
} | ||
} | ||
|
||
// process TO_BE_IMPORTED in parallel and add to validator manager. Change status to ERROR if | ||
// any error happens. | ||
final List<ImportKeystoreData> importedData = |
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.
It's a shame we need to iterate over the list multiple times. You could probably do a zip using mapToObj and an IntStream to just over the stream once.
i.e. something like
IntStream.range(0, parsedBody.getKeystores().size())
.mapToObj(i -> { create import keystore result; })
final String jsonKeystoreData = parsedBody.getKeystores().get(i); | ||
final String password = parsedBody.getPasswords().get(i); | ||
final String pubkey = getNormalizedPubKey(jsonKeystoreData); | ||
if (existingPubkeys.contains(pubkey)) { | ||
// keystore already loaded | ||
duplicateData.add( | ||
new ImportKeystoreData( | ||
i, pubkey, jsonKeystoreData, password, new ImportKeystoreResult(DUPLICATE))); | ||
} else { | ||
toBeImportedData.add( | ||
new ImportKeystoreData( | ||
i, pubkey, jsonKeystoreData, password, new ImportKeystoreResult(IMPORTED))); | ||
} | ||
} | ||
|
||
// process TO_BE_IMPORTED in parallel and add to validator manager. Change status to ERROR if | ||
// any error happens. | ||
final List<ImportKeystoreData> importedData = | ||
toBeImportedData.parallelStream() | ||
.peek( | ||
data -> { | ||
try { | ||
validatorManager.addValidator( | ||
data.getPubKeyBytes(), data.getKeystoreJson(), data.getPassword()); | ||
} catch (final Exception e) { | ||
data.setImportKeystoreResult( | ||
new ImportKeystoreResult( | ||
ImportKeystoreStatus.ERROR, | ||
"Error importing keystore: " + e.getMessage())); | ||
} | ||
}) | ||
.toList(); | ||
|
||
// clean out any error results | ||
removeSignersAndCleanupImportedKeystoreFiles( | ||
importedData.stream() | ||
.filter( | ||
data -> data.getImportKeystoreResult().getStatus() == ImportKeystoreStatus.ERROR) | ||
.map(ImportKeystoreData::getPubKey) | ||
.toList()); | ||
|
||
// merge duplicate and imported data and sort | ||
final List<ImportKeystoreResult> results = | ||
Stream.concat(duplicateData.stream(), importedData.stream()) | ||
.sorted() | ||
.map(ImportKeystoreData::getImportKeystoreResult) | ||
.toList(); | ||
|
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.
This block of code in the ImportKeystoresHandler.handle is getting very long and hard to read can this be broken up?
// process TO_BE_IMPORTED in parallel and add to validator manager. Change status to ERROR if | ||
// any error happens. | ||
final List<ImportKeystoreData> importedData = | ||
toBeImportedData.parallelStream() |
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.
Will using the parallelStream impact the performance on signing requests?
import org.apache.tuweni.bytes.Bytes; | ||
|
||
/** Keep the index of the keystore import json and password */ | ||
public class ImportKeystoreData implements Comparable<ImportKeystoreData> { |
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.
Could this be a record instead of a class?
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.
We might be able to convert this one to record as we need to modify the "ImportKeystoreResult" state to ERROR which is a member of this class.
CHANGELOG.md
Outdated
@@ -4,6 +4,7 @@ | |||
|
|||
### Bugs fixed | |||
- Ensure that Web3Signer stops the http server when a sigterm is received | |||
- Improve Key Manager API import operation to use parallel processing instead of serial processing. |
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.
think this is more of an improvement than a bug but you might disagree :)
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.
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.
will move it to Improvements section
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.
LGTM
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 a few minor comments, nothing blocking
.sorted() | ||
.map(ImportKeystoreData::getImportKeystoreResult) | ||
.toList(); | ||
// step 4: add validators to be imported in parallel stream |
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.
aren't we just importing here rather than "adding to be imported"?
Don't think we should mention the parallel stream implementation detail
context.fail(SERVER_ERROR, e); | ||
} | ||
} | ||
|
||
private String getNormalizedPubKey(final String json) { | ||
/** | ||
* Import validators in parallel stream |
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.
Do we need javadoc for a private method? If parallel stream is important here maybe rename the method?
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.
you are right, good observation, lets me rename the method.
getKeystoreDataToProcess(parsedBody, activePubKeys); | ||
|
||
// Step 3: import slashing protection data for all to-be-IMPORTED keys | ||
final List<String> importedPubKeys = getToBeImportedPubKeys(importKeystoreDataList); |
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.
s/importedPubKeys/pubKeysToBeImported ?
CHANGELOG.md
Outdated
@@ -4,6 +4,7 @@ | |||
|
|||
### Bugs fixed | |||
- Ensure that Web3Signer stops the http server when a sigterm is received | |||
- Improve Key Manager API import operation to use parallel processing instead of serial processing. |
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.
// load existing keys | ||
final Set<String> existingPubkeys = | ||
// load "active" keys | ||
final Set<String> activePubKeys = |
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.
Not clear to me what "active" means here and why that's significant for this code. Why is this better than "existingPubKeys"?
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.
The "active keys" term is used in the specs i.e https://github.com/ethereum/keymanager-APIs/tree/master/flows#import. For us, "active" means keys which are already loaded into memory before this API is called.
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've renamed it back to prior one.
@@ -103,26 +103,26 @@ public void handle(final RoutingContext context) { | |||
return; | |||
} | |||
|
|||
// load "active" keys | |||
final Set<String> activePubKeys = | |||
// "active" keys which are already loaded by Web3Signer before this import call. |
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.
👍
Co-authored-by: Simon Dudley <simon.dudley@consensys.net>
PR Description
Improve KeyManager API import operation. Process new validator in parallel instead of serial stream
Fixed Issue(s)
Documentation
doc-change-required
label to this PR if updates are required.Changelog
Testing