Report malice on sibling blocks from the same validator#165
Conversation
| /// modifications. | ||
| posdao_transition: Option<BlockNumber>, | ||
| /// History of block hashes recently received from peers. | ||
| received_block_hashes: RwLock<BTreeMap<(u64, Address), H256>>, |
There was a problem hiding this comment.
Trying to understand the code base better so I can contribute. Why this added to the ~AuthorityRound only and not AuthorityRoundParams?
There was a problem hiding this comment.
Because this is a run time map that is built from blocks received from the peers.
| if &new_hash != old_hash { | ||
| trace!(target: "engine", "Validator {} produced sibling blocks", header.author()); | ||
| self.validators.report_malicious(header.author(), set_number, header.number(), Default::default()); | ||
| Err(EngineError::SiblingBlocks(*header.author()))?; |
There was a problem hiding this comment.
I actually think we shouldn't return an error.
Because if the sender produced two sibling blocks, it could happen that the second one ends up getting finalized, so we need to make sure we import it. And the block itself isn't invalid, after all.
So I'd just log and report, and then continue.
|
|
| .read() | ||
| .iter() | ||
| .map(|(k, _)| k) | ||
| .filter(|(n, _)| *n < oldest_block_number) |
There was a problem hiding this comment.
Since a BTreeMap's keys are already ordered (and tuples are ordered lexicographically), it shouldn't be necessary to iterate through all of them. You could replace filter with take_while, or use range or split_off. (Not sure what's best.)
| .received_block_hashes | ||
| .read() | ||
| .iter() | ||
| .map(|(k, _)| k) |
There was a problem hiding this comment.
iter().map(|(k, _)| k) is equivalent to keys().
|
There is a problem with upgrading the |
| let received_block_hashes = self.received_block_hashes.read(); | ||
| received_block_hashes.get(&received_block_key).map(|h| h.clone()) | ||
| }; | ||
| if let Some(old_hash) = old_hash { |
There was a problem hiding this comment.
If we don't use old_hash elsewhere, we could just do this in one line:
if self.received_block_hashes.read().get(&received_block_key).any(|h| *h != new_hash) {|
Can we simulate somehow the producing of sibling blocks on the same step? (for testing purposes like we did for testing |
afck
left a comment
There was a problem hiding this comment.
Looks good! 👍
(Just a non-blocking nit-pick.)
| .ok_or(EngineError::FailedSystemCall("Failed to upgrade to BlockchainClient.".to_string()))?; | ||
|
|
||
| // Remove older block hash records. | ||
| let oldest_block_number = full_client.best_block_header().number().saturating_sub(100); |
There was a problem hiding this comment.
Let's turn 100 into a constant. (SIBLING_DETECTION_PERIOD? MALICE_REPORTING_HORIZON? DUPLICATE_BLOCK_SEARCH_LIMIT? A_BETTER_NAME_I_CANT_THINK_OF_RIGHT_NOW!)
|
But let's hold off merging until we've tested it, of course. |
a4c5f66 to
75c2be2
Compare
afck
left a comment
There was a problem hiding this comment.
(Just two more nit-picks, but nothing blocking.)
| Err(EngineError::DoubleVote(*header.author()))?; | ||
| } | ||
| // Report malice if the validator produced other sibling blocks in the same step. | ||
| let received_block_key = (header.number(), header.author().clone()); |
There was a problem hiding this comment.
I think Address is Copy:
| let received_block_key = (header.number(), header.author().clone()); | |
| let received_block_key = (header.number(), *header.author()); |
There was a problem hiding this comment.
Thanks! I rely on clippy too much in such cases, and it's not usable here at all.
| .collect(); | ||
| for k in keys_to_remove { | ||
| self.received_block_hashes.write().remove(&k); | ||
| } |
There was a problem hiding this comment.
Could this be simplified using BTreeMap::split_off?
let rbh = self.received_block_hashes.write();
let new_rbh = rbh.split_off((oldest_block_number, Address::zero()));
*rbh = new_rbh;|
Let's test this before merging
|
I'm working on this. |
eb340eb to
70f4ec6
Compare
70f4ec6 to
d00d1ac
Compare
|
Please don't merge this yet. It should be tested manually with |
d00d1ac to
89c5848
Compare
|
I had to rebase this, since |
|
@afck I wanted to test this PR with |
|
Closing in favor of #196. |
|
Thanks, I will test #196 |
Fixes #164