-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Include the seal when populating the header for a new block #11475
Conversation
Before this the `header_empty_steps_raw` would panic if the chain has already progressed beyond the block number set in `emptyStepsTransition`. As this is a user accessible configuration option I don't think we should panic.
Nothing really interesting here, renames or removes some methods. Adds some docs and extends a test a bit to clarify the behaviour of the code.
* master: Use parity-crypto updated to use upstream rust-secp256k1 (#11406) Cleanup some code in Aura (#11466) upgrade some of the dependencies (#11467) Some more release track changes to README.md (#11465) Update simple one-line installer due to switching to a single stable release track (#11463) update Dockerfile (#11461) Implement EIP-2124 (#11456)
@@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> { | |||
self.block.header.set_timestamp(header.timestamp()); | |||
self.block.header.set_uncles_hash(*header.uncles_hash()); | |||
self.block.header.set_transactions_root(*header.transactions_root()); | |||
self.block.header.set_seal(header.seal().to_vec()); |
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.
The fix for #11445 is here: without this the LockedBlock
built by enact()
lacks the seal and this causes the state root to be wrong.
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.
This doesn't seem right for me though. The idea with block types is that you go from:
OpenBlock -> ClosedBlock -> LockedBlock -> SealedBlock
and only the last type is guaranteed to have the seal.
How come the seal
is included in the state root anyway? It's two separate things and really I don't see a way how seal
affects the state
?
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.
Added comment + ref to this PR. It still feels a bit dirty to do this here and I'm open to alternatives.
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.
question: is this not called from Miner::seal_and_import_block_internally
code path? It seems like Miner::prepare_block
doesn't call populate_from
, correct?
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 I understand what you mean, but the reverse call-graph for populate_from()
looks like this:
populate_from() is called by…
enact() is called by…
enact_verified() is called by…
check_and_lock_block() is called by…
import_verified_blocks() is called by… (in impl Importer)
import_verified_blocks() is called by… (in impl ImportBlock for Client)
message() is called by… (ClientIoMessage::BlockVerified)
flush_queue()
In other words, populate_from()
is only called on the block verification path, not for block producing.
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.
cool, yeah that's what I meant.
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 need some clarifications on the original issue, but for me it seems unlikely that it actually affect state root
at all. However if we can prove that it actually solves the issue, then let's merge it but let's also add docs what the hell happens here.
@@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> { | |||
self.block.header.set_timestamp(header.timestamp()); | |||
self.block.header.set_uncles_hash(*header.uncles_hash()); | |||
self.block.header.set_transactions_root(*header.transactions_root()); | |||
self.block.header.set_seal(header.seal().to_vec()); |
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.
This doesn't seem right for me though. The idea with block types is that you go from:
OpenBlock -> ClosedBlock -> LockedBlock -> SealedBlock
and only the last type is guaranteed to have the seal.
How come the seal
is included in the state root anyway? It's two separate things and really I don't see a way how seal
affects the state
?
Oh, apologies. I just read the description and now I understand how |
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 to me, but wouldn't hurt to get another pair of eyes on this one because I'm not super intimate with 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.
changes lgtm. like @tomusdrw it also wasn't obvious to me the effects of the seal in state root calculation when we discussed this some days ago.
what I don't know is if this issue was always there or if it surfaced due to some recent change. I believe it must be the later because I tested the empty steps feature when I implemented it, and as it stands (before this PR) it is impossible to use it.
Co-Authored-By: André Silva <[email protected]>
Co-Authored-By: André Silva <[email protected]>
Co-Authored-By: André Silva <[email protected]>
Yeah, that's my biggest concern too: it must have been broken for quite while. I guess it's possible that users run old versions and haven't run into this yet. |
I still suspect this Clique Engine PR but I might be wrong :) |
* master: (27 commits) Faster kill_garbage (#11514) [EngineSigner]: don't sign message with only zeroes (#11524) fix compilation warnings (#11522) [ethcore cleanup]: various unrelated fixes from `#11493` (#11507) Add benchmark for transaction execution (#11509) Add Smart Contract License v1.0 Misc fixes (#11510) [dependencies]: unify `rustc-hex` (#11506) Activate on-chain randomness in POA Sokol (#11505) Grab bag of cleanup (#11504) Implement eth/64 (EIP-2364) and drop support for eth/62 (#11472) [dependencies]: remove `util/macros` (#11501) OpenEthereum bootnodes are added (#11499) [ci benches]: use `all-features` (#11496) [verification]: make test-build compile standalone (#11495) complete null-signatures removal (#11491) Include the seal when populating the header for a new block (#11475) fix compilation warnings (#11492) cargo update -p cmake (#11490) update to published rlp-derive (#11489) ...
Include the seal when populating the header for a new block so that the state root is calculated properly.
The issue here is that when
emptyStepTransition
andmaximumEmptySteps
are both set in the chain spec there are verification errors on block import, at Stage 5.A block is issued by a node and the other nodes can't verify it: state root mismatch.
Now, the Seal fields contain
EmptySteps
after the transition and each empty step implies a reward for the validator that emitted the empty step. This means that the accounts involved get touched, so the state root changes. Before that last step of the verification we callcheck_and_lock_block()
inclient.rs
which callsenact_verified()
which callsenact()
.enact()
essentially copies over data from the incoming block header (the one with the Seal with the EmptySteps) but before this PR it does not copy over the seal from the block being imported to the newly preparedLockedBlock
.The rewards are bestowed in
on_close_block()
and then the state is committed (which sets the state root).I think this is what is going on. I didn't use
LockedBlock::seal()
because it returns aSealedBlock
and I wasn't sure if we should change the return type tbh.Fixes #11445