-
Notifications
You must be signed in to change notification settings - Fork 37.7k
CKey: add Serialize and Unserialize #29295
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
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
Opened as draft because I suspect this can be done less verbosely. |
f2684ab
to
98ab264
Compare
Added |
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.
Concept ACK
src/key.h
Outdated
template<typename Stream> | ||
void Serialize(Stream &s) const { | ||
if (!fCompressed) { | ||
throw std::ios_base::failure("Uncompressed key"); |
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.
Is it not worth saving CKey::fCompressed
to disk as well and fully support ser/unser of any CKey
?
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.
Good point.
98ab264
to
84ac6c3
Compare
84ac6c3
to
8c067ef
Compare
Come to think of it, this PR only changes serialization, while #29307 deals with storage. So this is ready for review. |
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.
Code Review ACK 8c067ef
Notes:
- The Unserialise function first reads the compression flag from the stream and then updates the actual keydata.
- The Serialise function first writes the compression flag, followed by the keydata
- The test appropriately verifies the added code for both the compressed and uncompressed 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.
How is this different from CPrivKey
?
src/key.h
Outdated
inline void Unserialize(Stream& s) { | ||
s >> fCompressed; | ||
MakeKeyData(); | ||
s >> MakeWritableByteSpan(*keydata); |
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 sure. IIUC the assumption is that keydata should not hold invalid keys. Can you explain why this assumption should be broken?
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 CKey::Check()
on keydata[0]
?
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.
Done
Not familiar with the stratumv2 spec, but this seems odd to me and also not a good fit for |
I added
In Stratum v2 a pool or Template Provider (implemented in #28983) may (optionally) have an identity. This is necessary to prevent stealing hash rate (at least for the pool). In order to protect that identity in the long run, you can keep its private key on a different machine, generate a static key for the server and sign a certificate for that static key.
Why would you not use a
TIL. There's two issues with
With Stratum v2 you can just make a new static key if something goes wrong. It's more similar to how we handle Tor v3 and I2P private keys. It's possible to use the confusingly named
I could switch to OpenSSL encoding. Either by moving the code from @vasild wrote earlier:
I added this before, but given the existence of |
8c067ef
to
683f988
Compare
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.
ACK 683f988
683f988
to
3f11c15
Compare
I dropped support for uncompressed keys and added a comment to explain the difference with OpenSSL encoding. Also added test for invalid keys. |
3f11c15
to
0f5d0a6
Compare
src/key.h
Outdated
} | ||
|
||
template <typename Stream> | ||
inline void Unserialize(Stream& s) { |
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.
template implies inline
, so it can be removed. Also, could run clang-format on new code?
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.
Done. Would be nice to do this in a pre-commit hook or something, because it's unlikely I'm going to remember doing this every time.
src/key.h
Outdated
// Uncompressed keys should be OpenSSL serialized instead | ||
throw std::ios_base::failure("uncompressed key"); | ||
} | ||
::Serialize(s, MakeUCharSpan(*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.
Any reason to cast a byte span to a u-char span? I think you can replace all Make*Span()
by just Span{}
.
s << Span{*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.
Done in both places.
I really don't expect serializing and unserializing keys to disk (outside of the existing wallet use case) to be a common pattern. As @ryanofsky mentioned, I think it's good to have a little friction here to make the implementer think "should I really be doing this?"
I don't think it's fair to claim you are adding a standard method here. As I mentioned before:
But this PR is only adding yet another method, which is unnecessary considering your use case can be accomplished with the existing methods. |
By standard, I mean the same way we serialise other objects. I do agree it's not ideal to have multiple serialisation standards for the same object. A further refactor could address that, e.g. in a way similar to how we can serialize a CTransaction with or without witness ( |
I think a better approach would be to use the existing methods for your use case and then if we start seeing more use cases pop up where people absolutely need to serialize and unserialize raw |
As discussed a further above (#29295 (comment)) there's quite a few other things I need to get merged for Stratum v2 before this PR becomes a potential blocker. It's only at that point that I'll try other approaches. I'll mark this as draft for now. |
af25cfc
to
57fbd6c
Compare
Co-authored-by: Vasil Dimov <vd@FreeBSD.org>
57fbd6c
to
8d35a9b
Compare
In #28983 I need to read and write two private keys to/from disk that are used by Stratum v2 peers to (optionally) authenticate us.
For the write part, I initially just put the key data into a
std::vector<unsigned char>
and then used a modified version ofWriteBinaryFile
. But @vasild pointed out in #29229 that:This PR tries a different approach that hopefully addresses that. See Sjors#32 for how it's used (in
sv2_template_provider.cpp
).