-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Conversation
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.
first pass mostly LGTM, just the concerns about importing invalid ancient blocks. i'll take a more in-depth look tomorrow.
I'm really excited to try this out! Once it's merged we ought to spin up a couple servers and do a field test :)
let result = self.insert_unordered_block(&mut batch, bytes, receipts, parent_td, is_best, false); | ||
self.db.write(batch).unwrap(); | ||
result | ||
} |
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 function ought to just be removed and its usages replaced with insert_unordered_block.
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
@@ -415,6 +415,26 @@ impl Client { | |||
imported | |||
} | |||
|
|||
fn import_old_block(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> H256 { |
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 notice this doesn't do any block verification. are these blocks guaranteed to be part of a continuous chain to the first snapshot block at this point?
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.
see comments below
/// First block on the best sequence. | ||
pub first_block_hash: Option<H256>, | ||
/// Number of the first block on the best sequence. | ||
pub first_block_number: Option<BlockNumber>, |
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.
first block is guaranteed to exist. what does None
signify here?
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 None
to indicate that there's no gap in the blockchain. Blockchain always sets the value though.
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 seems fair, I see that's implemented now
} | ||
|
||
let result = if let Some(receipts) = receipts { | ||
io.chain().import_block_with_receipts(block, receipts) |
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 it safe to import directly here? we have no idea if the transactions contained within are valid
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 not much of an attack vector. These historical blocks are only used to be served to other peers. The attacker can't affect node's state with providing invalid data here.
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 it can't affect the state, it's probably best not to ever propagate potentially invalid blocks. other peers might detect that and label the offending node as bad
if let (Some(ancient_block_hash), Some(ancient_block_number)) = (chain.ancient_block_hash, chain.ancient_block_number) { | ||
|
||
trace!(target: "sync", "Downloading old blocks from {:?} (#{}) till {:?} (#{:?})", ancient_block_hash, ancient_block_number, chain.first_block_hash, chain.first_block_number); | ||
let mut downloader = BlockDownloader::new(true, &ancient_block_hash, ancient_block_number); |
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 BlockDownloader
here has no way of knowing whether the blocks it's getting from ancient_block_hash
onwards are actually going to lead up to the first block. Although these blocks never get enacted, it's probably best not to import any potentially invalid blocks.
For correctness, I would suggest having the block downloader proceed in two stages:
- Find a sparse hash-chain from the first block to the ancient block, built by walking in reverse (by 256? 512? 1024?) from the first block until the ancient block is reached.
- Walk this hash chain forward, fetching all necessary headers and ensuring that they have the right hash before importing.
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 agree that it is better to download the ancient chain in reverse, but will leave it for a future 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.
Ok, another PR sounds good. It should be a blocker for the 1.4 release, IMO.
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.
Note that if the blocks are being downloaded in reverse, no additional verification is needed.
the ancient block downloading is quite slow on my machine -- it keeps losing all its peers. it will need investigation. |
398fcc3
to
5d67bbf
Compare
38eae61
to
9aece51
Compare
@@ -160,7 +160,8 @@ | |||
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303", | |||
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303", | |||
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303", | |||
"enode://248f12bc8b18d5289358085520ac78cd8076485211e6d96ab0bc93d6cd25442db0ce3a937dc404f64f207b0b9aed50e25e98ce32af5ac7cb321ff285b97de485@zero.parity.io:30303" | |||
"enode://4cd540b2c3292e17cff39922e864094bf8b0741fcc8c5dcea14957e389d7944c70278d872902e3d0345927f621547efa659013c400865485ab4bfa0c6596936f@zero.parity.io:30303", | |||
"enode://cc92c4c40d612a10c877ca023ef0496c843fbc92b6c6c0d55ce0b863d51d821c4bd70daebb54324a6086374e6dc05708fed39862b275f169cb678e655da9d07d@136.243.154.246:30303" |
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.
aka antares.ethcore.io
@@ -1192,6 +1241,24 @@ impl BlockChain { | |||
body.append_raw(block_rlp.at(2).as_raw(), 1); | |||
body.out() | |||
} | |||
|
|||
/// Returns general blockchain information | |||
pub fn chain_info(&self) -> BlockChainInfo { |
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 is moved to blockchain.rs to make it atomic
BlockStatus::Unknown => { | ||
headers.push(try!(r.at(i)).as_raw().to_vec()); | ||
hashes.push(hash); | ||
self.old_blocks.as_mut().expect("Checked with condition above; qed") |
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.
why not just match on self.old_blocks.as_mut()
?
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
self.continue_sync(io); | ||
return Ok(()); | ||
} | ||
self.old_blocks.as_mut().expect("Checked with condition above; qed") |
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.
could also be rewritten with match
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
self.continue_sync(io); | ||
return Ok(()); | ||
} | ||
self.old_blocks.as_mut().expect("Checked with condition above; qed") |
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.
here as well
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
looks mostly good to me, just a couple minor grumbles. |
9aece51
to
d9e232b
Compare
haven't done a thorough review of the logic in the sync module. code in ethcore module could use some additional documentation. i think the full sync module would benefit from some high-level documentation to comprehend what all the moving parts are. can be in another PR though. |
The core syncing logic was not changed and is documented in |
Changes Unknown when pulling 544d20e on snapshot-sync into * on master*. |
[ci:skip]
In this PR:
block_sync
module. Now two of these run in parallel - one for the head of the chain and another one to download missing blocks for the blockchain gap.--warp
CLI optionRun with
--warp --bootnodes enode://cc92c4c40d612a10c877ca023ef0496c843fbc92b6c6c0d55ce0b863d51d821c4bd70daebb54324a6086374e6dc05708fed39862b275f169cb678e655da9d07d@136.243.154.246:30303
to teststill TODO: