-
Notifications
You must be signed in to change notification settings - Fork 36.7k
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
ECDSA signature optimization and more DoS prevention #1349
Conversation
Blown up by 6d64a0b, after merging by hand it dies because key.cpp doesn't #include <sync.h>. Introduces a harmless looking signed compare warning key.cpp:388:3. Have it running on a node now. |
Code appears correct to me. Comments inline... IMO push those refactors into the tree immediately. |
@jgarzik if your 'log-worthy event' comment is also on the oversized orphans (like 183 instead of 191), I thought the same thing. |
both, really |
Changes suggested by Sergio Demian Lerner to help prevent potential DoS attacks.
@gmaxwell : I want to keep this pull based on 0.6.2 in case we decide we need a 0.6.3. @jgarzik : ACK, I'll fix the comments. I think encapsulation in a class is overkill. @SergioDemianLerner : excellent catch on vSpent, and I 100% agree this code needs extremely careful review and as much testing as we can throw at it. I also like your suggestion to only cache valid signatures; it has the added benefit of making the code a lot simpler. |
Remove orphan transactions from memory once all of their parent transactions are received and they're still not valid. Thanks to Sergio Demian Lerner for suggesting this fix.
Loop over all inputs doing inexpensive validity checks first, and then loop over them a second time doing expensive signature checks. This helps prevent possible CPU exhaustion attacks where an attacker tries to make a victim waste time checking signatures for invalid transactions.
Create a maximum-10MB signature verification result cache. This should almost double the number of transactions that can be processed on a given CPU, because before this change ECDSA signatures were verified when transactions were added to the memory pool and then again when they appeared in a block.
ACK |
Gavin: can you estimate the time it takes to verify a signature compared to the time it takes to get the result from the cache? There should be a factor of at least 100x between them, but the test code seems to disagree with this. |
@SergioDemianLerner I'll isolate and benchmark the cache unit test to see why cached signatures are taking 50ms to validate. Note that all of the CScript interpreter machinery is still being run (I am testing/measuring at the VerifySignature() level, not a the CKey:: level). |
What I did: Used valgrind --tool=callgrind and hacked versions of test/DoS_tests.cpp to isolate and measure just the cached signature verification code. What I found: Two things slow down cached signature verification:
Finally, in the future very-high-level optimization schemes for transactions might be implemented; for example, if you have a peer that you can completely trust to give you only valid transactions then you could skip all verifications and take it on faith that all transactions from that peer are valid (with, perhaps, a random 1-in-100 audit to make sure the peer hasn't been corrupted). So spending a lot of time on micro-optimizations may not be the best way forward. |
Great! A lot of useful information! |
@SergioDemianLerner Thats actually a bad idea. Otherwise I can just create endless numbers of scripts of the form push $randomnumber pop [normal script] with no computation on my part in order to bypass the cache. |
We're caching only the scripts that verify ok so that kind of attack does not work. |
Also I had suggested caching (outpoint,hash(script)) -> bool to reduce memory consumption. |
@SergioDemianLerner PUSH $randomnumber POP {normal script} will also validate if {normal script} would have also validated— but it will have a different hash. |
See follow-up pull #1380. |
@gmaxwell You are right. Scripts cannot be easily cached. We would need an pushdown automata parser and optimizer to compress scripts and erase all garbage. |
Although IsStandard() check would prevent "PUSH $randomnumber POP {normal script}" scripts from being forwarded, so it may be possible to cache at that level too. |
@SergioDemianLerner I picked a toy example, and besides, we wouldn't want to adopt a design which strongly discouraged expanding IsStandard in the future. |
ACK. |
Replacing 'bitcoins' in tooltip
These 6 commits:
Tested by: