Skip to content

Commit a5e1d0b

Browse files
committed
Refactor sync state transition
1 parent 8a428cb commit a5e1d0b

File tree

1 file changed

+84
-51
lines changed

1 file changed

+84
-51
lines changed

sync/src/block/extension.rs

Lines changed: 84 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,64 @@ enum State {
7575
Full,
7676
}
7777

78+
impl State {
79+
fn initial(client: &Client, snapshot_target: Option<(BlockHash, u64)>) -> Self {
80+
let (hash, num) = match snapshot_target {
81+
Some(target) => target,
82+
None => return State::Full,
83+
};
84+
let header = match client.block_header(&num.into()) {
85+
Some(ref h) if h.hash() == hash => h.clone(),
86+
_ => return State::SnapshotHeader(hash, num),
87+
};
88+
if client.block_body(&hash.into()).is_none() {
89+
let parent_hash = header.parent_hash();
90+
let parent =
91+
client.block_header(&parent_hash.into()).expect("Parent header of the snapshot header must exist");
92+
return State::SnapshotBody {
93+
header,
94+
prev_root: parent.transactions_root(),
95+
}
96+
}
97+
98+
let state_db = client.state_db().read();
99+
let state_root = header.state_root();
100+
match TrieFactory::readonly(state_db.as_hashdb(), &state_root) {
101+
Ok(ref trie) if trie.is_complete() => State::Full,
102+
_ => State::SnapshotChunk {
103+
block: hash,
104+
restore: SnapshotRestore::new(state_root),
105+
},
106+
}
107+
}
108+
109+
fn next(&self, client: &Client) -> Self {
110+
match self {
111+
State::SnapshotHeader(hash, _) => {
112+
let header = client.block_header(&(*hash).into()).expect("Snapshot header is imported");
113+
let parent = client
114+
.block_header(&header.parent_hash().into())
115+
.expect("Parent of the snapshot header must be imported");
116+
State::SnapshotBody {
117+
header,
118+
prev_root: parent.transactions_root(),
119+
}
120+
}
121+
State::SnapshotBody {
122+
header,
123+
..
124+
} => State::SnapshotChunk {
125+
block: header.hash(),
126+
restore: SnapshotRestore::new(header.state_root()),
127+
},
128+
State::SnapshotChunk {
129+
..
130+
} => State::Full,
131+
State::Full => State::Full,
132+
}
133+
}
134+
}
135+
78136
pub struct Extension {
79137
state: State,
80138
requests: HashMap<NodeId, Vec<(u64, RequestMessage)>>,
@@ -100,7 +158,7 @@ impl Extension {
100158
) -> Extension {
101159
api.set_timer(SYNC_TIMER_TOKEN, Duration::from_millis(SYNC_TIMER_INTERVAL)).expect("Timer set succeeds");
102160

103-
let state = Extension::initial_state(client.clone(), snapshot_target);
161+
let state = State::initial(&client, snapshot_target);
104162
cdebug!(SYNC, "Initial state is {:?}", state);
105163
let mut header = client.best_header();
106164
let mut hollow_headers = vec![header.decode()];
@@ -138,34 +196,29 @@ impl Extension {
138196
}
139197
}
140198

141-
fn initial_state(client: Arc<Client>, snapshot_target: Option<(BlockHash, u64)>) -> State {
142-
let (hash, num) = match snapshot_target {
143-
Some(target) => target,
144-
None => return State::Full,
145-
};
146-
let header = match client.block_header(&num.into()) {
147-
Some(ref h) if h.hash() == hash => h.clone(),
148-
_ => return State::SnapshotHeader(hash, num),
149-
};
150-
if client.block_body(&hash.into()).is_none() {
151-
let parent_hash = header.parent_hash();
152-
let parent =
153-
client.block_header(&parent_hash.into()).expect("Parent header of the snapshot header must exist");
154-
return State::SnapshotBody {
155-
header,
156-
prev_root: parent.transactions_root(),
199+
fn move_state(&mut self) {
200+
let next_state = self.state.next(&self.client);
201+
cdebug!(SYNC, "Transitioning the state to {:?}", next_state);
202+
if discriminant(&next_state) == discriminant(&State::Full) {
203+
let best_hash = match &self.state {
204+
State::SnapshotHeader(hash, _) => *hash,
205+
State::SnapshotBody {
206+
header,
207+
..
208+
} => header.hash(),
209+
State::SnapshotChunk {
210+
block,
211+
..
212+
} => *block,
213+
State::Full => unreachable!("Trying to transition state from State::Full"),
214+
};
215+
self.client.force_update_best_block(&best_hash);
216+
for downloader in self.header_downloaders.values_mut() {
217+
downloader.update_pivot(best_hash);
157218
}
219+
self.send_status_broadcast();
158220
}
159-
160-
let state_db = client.state_db().read();
161-
let state_root = header.state_root();
162-
match TrieFactory::readonly(state_db.as_hashdb(), &state_root) {
163-
Ok(ref trie) if trie.is_complete() => State::Full,
164-
_ => State::SnapshotChunk {
165-
block: hash,
166-
restore: SnapshotRestore::new(state_root),
167-
},
168-
}
221+
self.state = next_state;
169222
}
170223

171224
fn dismiss_request(&mut self, id: &NodeId, request_id: u64) {
@@ -476,8 +529,7 @@ impl NetworkExtension<Event> for Extension {
476529
if let Some(root) = restore.next_to_feed() {
477530
self.send_chunk_request(&block, &root);
478531
} else {
479-
self.client.force_update_best_block(&block);
480-
self.transition_to_full();
532+
self.move_state();
481533
}
482534
}
483535
State::Full => {
@@ -863,11 +915,7 @@ impl Extension {
863915
return
864916
}
865917
}
866-
self.state = State::SnapshotBody {
867-
header: EncodedHeader::new(header.rlp_bytes().to_vec()),
868-
prev_root: *parent.transactions_root(),
869-
};
870-
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
918+
self.move_state();
871919
}
872920
_ => cdebug!(
873921
SYNC,
@@ -941,11 +989,7 @@ impl Extension {
941989
};
942990
match self.client.import_trusted_block(&block) {
943991
Ok(_) | Err(BlockImportError::Import(ImportError::AlreadyInChain)) => {
944-
self.state = State::SnapshotChunk {
945-
block: header.hash(),
946-
restore: SnapshotRestore::new(header.state_root()),
947-
};
948-
cdebug!(SYNC, "Transitioning state to {:?}", self.state);
992+
self.move_state();
949993
}
950994
Err(BlockImportError::Import(ImportError::AlreadyQueued)) => {}
951995
// FIXME: handle import errors
@@ -1051,20 +1095,9 @@ impl Extension {
10511095
if let Some(root) = restore.next_to_feed() {
10521096
self.send_chunk_request(&block, &root);
10531097
} else {
1054-
self.client.force_update_best_block(&block);
1055-
self.transition_to_full();
1098+
self.move_state();
10561099
}
10571100
}
1058-
1059-
fn transition_to_full(&mut self) {
1060-
cdebug!(SYNC, "Transitioning state to {:?}", State::Full);
1061-
let best_hash = self.client.best_block_header().hash();
1062-
for downloader in self.header_downloaders.values_mut() {
1063-
downloader.update_pivot(best_hash);
1064-
}
1065-
self.state = State::Full;
1066-
self.send_status_broadcast();
1067-
}
10681101
}
10691102

10701103
pub struct BlockSyncSender(EventSender<Event>);

0 commit comments

Comments
 (0)