-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Protocol Amendment: Always Require Fully-Canonical Signatures #3256
Conversation
Incidentally, first #XRPCommunity amendment? |
Codecov Report
@@ Coverage Diff @@
## develop #3256 +/- ##
===========================================
- Coverage 70.33% 70.12% -0.21%
===========================================
Files 675 674 -1
Lines 53178 53612 +434
===========================================
+ Hits 37402 37598 +196
- Misses 15776 16014 +238
Continue to review full report at Codecov.
|
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.
Lean and mean. I like this. But it needs more thorough unit tests.
src/ripple/protocol/impl/STTx.cpp
Outdated
@@ -186,7 +187,7 @@ std::pair<bool, std::string> STTx::checkSign() const | |||
// at the SigningPubKey. It it's empty we must be | |||
// multi-signing. Otherwise we're single-signing. | |||
Blob const& signingPubKey = getFieldVL (sfSigningPubKey); | |||
ret = signingPubKey.empty () ? checkMultiSign () : checkSingleSign (); | |||
ret = signingPubKey.empty () ? checkMultiSign (rules) : checkSingleSign (rules); |
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 think that for these two private
member functions, it's a better idea to pass an actual bool
instead of the actual Rules
object.
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.
Only if you consider Ripple not as a part of the community. ;-) |
The non-unity CI builds are failing. It looks like, at a minimum, STTx.cpp is missing an include of Feature.h. Here the the output from the one of the non-unity builds:
|
@nbougalis could you advise as to how to generate non-canonical signatures for testing purposes? Can ripple-lib be modified to do so? |
D'oh! Should've said first non-ripple #XRPCommunity ammendment! 🤦♂️ |
Pushed a followon patch fixing the unity build |
I don't think ripple-lib can generate non-canonical signatures. It may be possible to modify it to do so, but I'm not knowledgeable about how to do that. Searches turned up the following resources, in case they are helpful. I imagine @nbougalis knows more. |
First and foremost, thanks for doing this! I think you've made a great change. This is yet another case where you're doing something that we should have taken care of years ago. I appreciate it. That said, there are a couple of changes that I think need to be made. They are:
I haven't actually tried turning a fully-canonical signature into a non-fully-canonical signature using this technique. So I can't guarantee that it will work. Also, if you feel like figuring this out is above and beyond the call of duty then let me know and I'll try to put together a couple of unit tests. I think you have a good change here. It's very much worth my time to help you get this change into the code base. Let me know if you want any help. And thanks again. |
@nbougalis @scottschurr OK I was able to generate a TX w/ a non-fully-canonical signature (also w/out the tfFullyCanonicalSig flag). I pushed a follow on patch adding a test case w/ that, verifying the transaction fails to be verified when the amendment is enabled, and succeeds when that amendment is disabled. Also cherry picked @scottschurr's patch introducing the new "RequireFullyCanonicalSig" enum and added a followon patch updating the test case to use that. Let me know if there is anything else! |
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.
Hi @movitto. I really appreciate you adding the uint test. And it's so close. But it doesn't actually test the change that you're adding. What you're adding is an amendment that, before it's passed, will allow a non-fully-canonically-signed transaction to slip through the system. Once the amendment is passed the non-fully-canonically-signed transaction should no longer be accepted.
Your unit test doesn't actually exercise the amendment itself. That's what I think we really want. Does that distinction make sense? If not let me know and I'll see if I can explain it better.
Thanks again for your work on this change. Once the unit test is in order I think this pull request will be good to go.
src/test/protocol/STTx_test.cpp
Outdated
{ | ||
// Construct a payments w/out a fully-canonical tx | ||
const std::string non_fully_canonical_tx = | ||
"12000022000000002400000001201B00497D9C6140000000000F695068400000000000000C732103767C7B2C13AD90050A4263745E4BAB2B975417FA22E87780E1506DDAF21139BE74483046022100E95670988A34C4DB0FA73A8BFD6383872AF438C147A62BC8387406298C3EADC1022100A7DC80508ED5A4750705C702A81CBF9D2C2DC3AFEDBED37BBCCD97BC8C40E08F8114E25A26437D923EEF4D6D815DF93368B62E6440848314BB85996936E4F595287774684DC2AC6266024BEF"; |
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.
Nit: This is a really long line. You can preserve the string and still limit the line(s) to 80 characters. The compiler concatenates consecutive string literals that are not separated by commas. So you can build the string literal like this:
// Construct a payments w/out a fully-canonical tx
const std::string non_fully_canonical_tx =
"12000022000000002400000001201B00497D9C6140000000000F6950684000000"
"00000000C732103767C7B2C13AD90050A4263745E4BAB2B975417FA22E87780E1"
"506DDAF21139BE74483046022100E95670988A34C4DB0FA73A8BFD6383872AF43"
"8C147A62BC8387406298C3EADC1022100A7DC80508ED5A4750705C702A81CBF9D"
"2C2DC3AFEDBED37BBCCD97BC8C40E08F8114E25A26437D923EEF4D6D815DF9336"
"8B62E6440848314BB85996936E4F595287774684DC2AC6266024BEF";
Note that the example I'm giving indents the string literal by four spaces, not two, since this is an indent-by-four-spaces code base.
src/test/protocol/STTx_test.cpp
Outdated
{ | ||
bool valid = tx.checkSign(STTx::RequireFullyCanonicalSig::no).first; | ||
if(!valid) | ||
fail("Non-Fully canoncial signature was not permitted"); |
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.
Nit: this and the following fail
should be indented by four, not two, spaces.
vs testing it via internal helpers
@scottschurr pushed a patch testing the acceptability of non-canonical txs via the enablement of the amendment vs the state of the boolean in the internal helpers. Also fixes the style issues you pointed out. I believe this addresses the items you pointed out, let me know if otherwise |
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.
👍 Looks great. Thanks for your persistence with the unit test.
@nbougalis, are you good with the unit test? If so, then I think this is good to go.
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.
Looks good, thanks. Left two micro-nits that I'd like to see addressed.
src/ripple/app/tx/impl/apply.cpp
Outdated
STTx::RequireFullyCanonicalSig const requireCanonicalSig = | ||
rules.enabled(featureRequireFullyCanonicalSig) ? | ||
STTx::RequireFullyCanonicalSig::yes : | ||
STTx::RequireFullyCanonicalSig::no; | ||
|
||
auto const sigVerify = tx.checkSign(requireCanonicalSig); |
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'd prefer: auto const requireCanonicalSig = ... whatever ...
instead of STTx::RequireFullyCanonicalSig const requireCanonicalSig = ... whatever ...
.
Rationale: the precise type of the variable here is irrelevant and doesn't add much. This is, ultimately, a bool
with some type-safety and user-friendliness sprinked on it, and a programmer can deduce the actual type by examining the ternary.
src/ripple/protocol/impl/STTx.cpp
Outdated
bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig); | ||
bool const fullyCanonical = | ||
(getFlags() & tfFullyCanonicalSig) || | ||
(requireCanonicalSig != RequireFullyCanonicalSig::no); |
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'd prefer requireCanonicalSig == RequireFullyCanonicalSig::yes
here (and below in checkMultiSign
). It makes it easier to read and inverting the check just makes it harder (at least for me) to reason about 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.
I hear the argument. Personally, I picked != no
because I know that it's possible for a bool
to have values other than 0 and 1. So in case there's something unexpected in the bool
it will set fullyCanonical == true
. Using == yes
doesn't give that guarantee.
But I don't feel strongly about it. The case is pretty unlikely.
aedf91a
@nbougalis pushed a followup patch incorporating your feedback |
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.
👍
Linux build OK after rebasing on 1.5.0-b5, unit tests passed. |
Addresses #3042 by adding an amendment which if enabled would require full-canonical signatures regardless of whether or not the tfFullyCanonicalSig flag is set. Existing functionality will be preserved if amendment is not enabled.