feat(core): implement consensus/qbft/msg#442
Conversation
|
@claude review this for me |
|
Claude finished @iamquang95's task in 4m 38s —— View job Claude PR Review — feat(core): implement consensus/qbft/msgTodos:
Overall this is a clean, well-documented port that mirrors Functional correctness1. In Go ( This is fine iff receive-side validation rejects unknown types before they reach 2. The Go equivalent (
Code quality3.
if M::PACKAGE == "google.protobuf" && M::NAME == "Any" {
return Err(Error::CannotHashAnyProto);
}
4.
Tests5.
6. No round-trip test for re-signing. The doc on 7. No tampering test for Nits
VerdictLGTM after addressing 1, 2, and ideally 3. Items 4–7 are quality-of-life improvements that can land in a follow-up. |
varex83agent
left a comment
There was a problem hiding this comment.
Summary
This PR ports core/consensus/qbft/msg.go from Charon v1.7.1 to Pluto Rust as crates/core/src/consensus/qbft/msg.rs. The functional parity is solid: Msg::new, hash_proto, sign_msg, verify_msg_sig, and to_hash32 all map cleanly to their Go counterparts, golden-vector tests (UNSIGNED_DATASET_HASH, QBFT_MSG_HASH, QBFT_MSG_SIGNATURE) lock in cross-language byte parity, and the test surface meaningfully expands on Charon's (parametric hash cases, deterministic-encoding regression, sign/verify roundtrip with fixed keys). All 27 new tests pass locally.
Bugs (must-fix)
- Debug-formatting a
Msgwith an unknown wiretypepanics the task (crates/core/src/consensus/qbft/msg.rs:119).Msg::fmtcallsMessageType::from_wire(self.msg.r#type).to_string(), and the new publicfrom_wireconstructor preserves anyi64without clamping — butMessageType'sDisplayimpl panics for any value outside0..=5. SinceMsg::newdoes not validater#type, a peer can construct aMsgwhoseDebugrepresentation aborts the process. This is reachable from anytracingsite or logger that touches a wrapped message, andDebugshould never panic.
Major findings
None beyond the bug above.
Minor / nit findings
Closely related to the bug: MessageType::Display itself is the root cause (panic on the catch-all arm), and Msg::new should arguably reject !MessageType::valid() rather than relying on upstream filters. Other findings cover documented divergences from Charon (closed-enum DutyType projection, empty-vs-nil signature semantics), Rust-style polish (wider pub visibility than Go, missing #[source] on wrapped errors, double-wrap in trait value_source), an efficiency concern (#[derive(Clone)] deep-copies protobufs that Go shares by pointer), and a small test gap (no malformed-but-non-empty signature case).
Verdict
Request changes for the Debug/Display panic — easy fix (have Display fall back to unknown({n}) or branch on valid() in Msg::fmt). The rest is non-blocking and at author discretion.
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; |
There was a problem hiding this comment.
nit: test-module imports are not grouped consistently with the production file (std::* / external / crate::* separated by blank lines on lines 23-33). Trivial to align: use super::*; and use crate::qbft::{...}; in one group, use prost::bytes::Bytes; use prost_types::Timestamp; use test_case::test_case; in another.
| /// Justifications are raw protobuf messages from the same consensus | ||
| /// envelope. They are recursively wrapped with the same shared value map. | ||
| pub(crate) fn new( | ||
| msg: Option<pbconsensus::QbftMsg>, |
There was a problem hiding this comment.
I wonder if we need optional msg here, if passing without it returns an error in the first line of the function. I might be better to not call new at all in this case.
There was a problem hiding this comment.
Agree that we can change this to msg: pbconsensus::QbftMsg, the option is just charon compability API (they use pointer). I will change this in #448
Part of: #157