Skip to content

Commit 77e5bb2

Browse files
committed
Add Commit message in Tendermint
Before this commit, Tendermint extension only requests current height and view's votes. Handling only the current view's message makes code simple. However, there may be a commit before the current view. This creates a liveness problem. After this commit, a node requests a Commit message if some of its peer's height is higher than the node. The commit message is not related to the node's current view. The Commit message fixes the liveness problem.
1 parent 2b12d0b commit 77e5bb2

File tree

3 files changed

+381
-0
lines changed

3 files changed

+381
-0
lines changed

core/src/consensus/tendermint/message.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ const MESSAGE_ID_PROPOSAL_BLOCK: u8 = 0x02;
7979
const MESSAGE_ID_STEP_STATE: u8 = 0x03;
8080
const MESSAGE_ID_REQUEST_MESSAGE: u8 = 0x04;
8181
const MESSAGE_ID_REQUEST_PROPOSAL: u8 = 0x05;
82+
const MESSAGE_ID_REQUEST_COMMIT: u8 = 0x06;
83+
const MESSAGE_ID_COMMIT: u8 = 0x07;
8284

8385
#[derive(Debug, PartialEq)]
8486
pub enum TendermintMessage {
@@ -102,6 +104,13 @@ pub enum TendermintMessage {
102104
height: Height,
103105
view: View,
104106
},
107+
RequestCommit {
108+
height: Height,
109+
},
110+
Commit {
111+
block: Bytes,
112+
votes: Vec<ConsensusMessage>,
113+
},
105114
}
106115

107116
impl Encodable for TendermintMessage {
@@ -160,6 +169,22 @@ impl Encodable for TendermintMessage {
160169
s.append(height);
161170
s.append(view);
162171
}
172+
TendermintMessage::RequestCommit {
173+
height,
174+
} => {
175+
s.begin_list(2);
176+
s.append(&MESSAGE_ID_REQUEST_COMMIT);
177+
s.append(height);
178+
}
179+
TendermintMessage::Commit {
180+
block,
181+
votes,
182+
} => {
183+
s.begin_list(3);
184+
s.append(&MESSAGE_ID_COMMIT);
185+
s.append(block);
186+
s.append_list(votes);
187+
}
163188
}
164189
}
165190
}
@@ -253,6 +278,34 @@ impl Decodable for TendermintMessage {
253278
view,
254279
}
255280
}
281+
MESSAGE_ID_REQUEST_COMMIT => {
282+
let item_count = rlp.item_count()?;
283+
if item_count != 2 {
284+
return Err(DecoderError::RlpIncorrectListLen {
285+
got: item_count,
286+
expected: 2,
287+
})
288+
}
289+
let height = rlp.at(1)?.as_val()?;
290+
TendermintMessage::RequestCommit {
291+
height,
292+
}
293+
}
294+
MESSAGE_ID_COMMIT => {
295+
let item_count = rlp.item_count()?;
296+
if item_count != 3 {
297+
return Err(DecoderError::RlpIncorrectListLen {
298+
got: item_count,
299+
expected: 3,
300+
})
301+
}
302+
let block = rlp.at(1)?.as_val()?;
303+
let votes = rlp.at(2)?.as_list()?;
304+
TendermintMessage::Commit {
305+
block,
306+
votes,
307+
}
308+
}
256309
_ => return Err(DecoderError::Custom("Unknown message id detected")),
257310
})
258311
}
@@ -408,6 +461,42 @@ mod tests {
408461
});
409462
}
410463

464+
#[test]
465+
fn encode_and_decode_tendermint_message_6() {
466+
rlp_encode_and_decode_test!(TendermintMessage::RequestCommit {
467+
height: 3,
468+
});
469+
}
470+
471+
#[test]
472+
fn encode_and_decode_tendermint_message_7() {
473+
rlp_encode_and_decode_test!(TendermintMessage::Commit {
474+
block: vec![1u8, 2u8],
475+
votes: vec![
476+
ConsensusMessage {
477+
signature: SchnorrSignature::random(),
478+
signer_index: 0x1234,
479+
on: VoteOn {
480+
step: VoteStep::new(2, 3, Step::Commit),
481+
block_hash: Some(H256::from(
482+
"07feab4c39250abf60b77d7589a5b61fdf409bd837e936376381d19db1e1f050"
483+
)),
484+
},
485+
},
486+
ConsensusMessage {
487+
signature: SchnorrSignature::random(),
488+
signer_index: 0x1235,
489+
on: VoteOn {
490+
step: VoteStep::new(2, 3, Step::Commit),
491+
block_hash: Some(H256::from(
492+
"07feab4c39250abf60b77d7589a5b61fdf409bd837e936376381d19db1e1f050"
493+
)),
494+
},
495+
}
496+
]
497+
});
498+
}
499+
411500
#[test]
412501
fn encode_and_decode_consensus_message_1() {
413502
let message = ConsensusMessage::default();

core/src/consensus/tendermint/network.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,43 @@ impl NetworkExtension<Event> for TendermintExtension {
352352
self.send_votes(token, votes);
353353
}
354354
}
355+
Ok(TendermintMessage::RequestCommit {
356+
height,
357+
}) => {
358+
ctrace!(ENGINE, "Received RequestCommit for {} from {:?}", height, token);
359+
let (result, receiver) = crossbeam::bounded(1);
360+
self.inner
361+
.send(worker::Event::RequestCommit {
362+
height,
363+
result,
364+
})
365+
.unwrap();
366+
367+
if let Ok(message) = receiver.recv() {
368+
ctrace!(ENGINE, "Send commit for {} to {:?}", height, token);
369+
self.api.send(token, Arc::new(message));
370+
}
371+
}
372+
Ok(TendermintMessage::Commit {
373+
block,
374+
votes,
375+
}) => {
376+
ctrace!(ENGINE, "Received Commit from {:?}", token);
377+
let (result, receiver) = crossbeam::bounded(1);
378+
self.inner
379+
.send(worker::Event::GetCommit {
380+
block: block.clone(),
381+
votes,
382+
result,
383+
})
384+
.unwrap();
385+
386+
if let Some(c) = receiver.recv().unwrap() {
387+
if let Err(e) = c.import_block(block) {
388+
cinfo!(ENGINE, "Failed to import committed block {:?}", e);
389+
}
390+
}
391+
}
355392
_ => cinfo!(ENGINE, "Invalid message from peer {}", token),
356393
}
357394
}

0 commit comments

Comments
 (0)