-
Notifications
You must be signed in to change notification settings - Fork 797
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
Batch state blocks signatures verification #956
Conversation
Very nice! I'll take a look in a bit, if anyone else can too that'd be good. |
rai/lib/numbers.cpp
Outdated
messages_pointers[i] = messages[i].bytes.data (); | ||
messages_lengths[i] = sizeof (messages[i].bytes); | ||
public_keys_pointers[i] = public_keys[i].bytes.data (); | ||
signatures_pointers[i] = signatures[i].bytes.data (); |
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 to prevent an additional copy here. Could we change the function signature to require C style arrays of arrays of bytes?
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.
Sure we can
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.
While you're at it, where it's called from, instead of copying the e.g. signature bytes we could just make an array of pointers to them.
This PR is exciting! I'm worried about messing with signature verification, as that's a very critical piece of code, but this looks good to me. Does this speed up bootstrapping? |
While it's increasing verification speed up to 40-50% for large amounts of state blocks (I forget to add old test --debug_verify_profile_batch, thx for reminder), currently only 14.4% of blocks are state. So it won't increase current bootstrap speed significantly |
I can confirm a max 40-60% speedup from my batch verification experiments. Increasing the batch size beyond the default (64 i think) doesn't help much either. |
What about this process:
|
Seems valid process |
Still I think that signature verification shouldn't be removed from ledger processor by default because other functions can use it except block_processor::process_receive_many |
MSVC conforms to C90 standards and does not support variable length arrays (C99) which is what is causing the appveyor failures |
Until variable length arrays support or better VLA emulation
State blocks with epoch links != epoch blocks Validate all blocks with epoch link by common rules
rai/node/node.cpp
Outdated
{ | ||
if (!rai::work_validate (block_a->root (), block_a->block_work ())) | ||
{ | ||
std::lock_guard<std::mutex> lock (mutex); | ||
if (blocks_hashes.find (block_a->hash ()) == blocks_hashes.end ()) | ||
{ | ||
blocks.push_back (std::make_pair (block_a, origination)); | ||
blocks_hashes.insert (block_a->hash ()); | ||
if (!unchecked && block_a->type () == rai::block_type::state && block_a->link () != node.ledger.epoch_link) |
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 the unchecked
parameter is named incorrectly. Shouldn't it be called checked
? If it's true, it bypasses signature validation.
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.
Can we construct a test on that?
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.
Well, probably require renaming. Parameter for state blocks from unchecked table. As all state blocks in unchecked already was validated
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 see. Is the performance improvement worth the risk?
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 guess yes. Rare risks are signature corruption on disk in unchecked table or bit flips. Same risk for state blocks table & usual signature check.
But this can be moved to separate PR
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.
In terms of risk I was thinking we might accidentally put unvalidated blocks in the unchecked table.
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.
Though I think I've brought this up before. Either way should be fine.
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.
As far as I see unchecked_put used only with previous_gap or source_gap, that status goes after signature checks for state blocks
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.
Let’s go with the safer option. Can we make a test that has a block with a bad signature in unchecked and make sure it isn’t processed?
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.
Unchecked thing removed. I guess we can return to this after 17.0, now better polish what we have for new release
Other than that LGTM |
for future different PR to reduce CPU load
@@ -1440,6 +1460,11 @@ rai::block_hash rai::receive_block::root () const | |||
return hashables.previous; | |||
} | |||
|
|||
rai::block_hash rai::receive_block::link () const | |||
{ | |||
return 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.
Should we assert(false)
here (or just not implement this virtual function for non-state blocks) ? The receive block probably has the equivalent of a link
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.
That's similar to source (), previous () & some other functions returning 0 for some block types. We can just not implement such functions when they return 0 I guess to save some lines in 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.
Is this a case of using release_assert since we shouldn’t be looking for the link of non-state blocks?
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.
Either release_assert() or not declaring the virtual methods for these block types which should generate a fatal exception
rai/node/node.cpp
Outdated
@@ -1051,7 +1102,7 @@ void rai::block_processor::process_receive_many (std::unique_lock<std::mutex> & | |||
node.ledger.rollback (transaction, successor->hash ()); | |||
} | |||
} | |||
auto process_result (process_receive_one (transaction, block.first, block.second)); | |||
auto process_result (process_receive_one (transaction, block.first, block.second, !force)); |
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.
Using !force
here is not clear that it's directly related to state blocks... can we do something more clear ?
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.
Forced state blocks are not validated in verify_state_blocks () function
Because of that we should set set validated_state_block as "false" for forced blocks (!force)
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.
But !force
will evaluate to true when force
is false which can happen for things other than state blocks (or verified blocks ?)
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.
Yes, but only state blocks vefirication can be skipped by flag in ledger.processor
Awesome work ! |
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.
Thanks !
No description provided.