@@ -8,10 +8,11 @@ use serde::{Deserialize, Serialize};
88
99use super :: {
1010 boxed_format:: BoxedFormat ,
11- errors:: { LocalError , ReceiveError } ,
11+ errors:: { LocalError , ProtocolValidationError , ReceiveError } ,
1212 message:: { DirectMessage , EchoBroadcast , NormalBroadcast , ProtocolMessage , ProtocolMessagePart } ,
1313 round:: {
14- Artifact , CommunicationInfo , DynTypeId , FinalizeOutcome , PartyId , Payload , Protocol , ProtocolError , Round ,
14+ Artifact , CommunicationInfo , DynTypeId , FinalizeOutcome , PartyId , Payload , Protocol , ProtocolError ,
15+ RequiredMessages , Round ,
1516 } ,
1617 round_id:: { RoundId , TransitionInfo } ,
1718} ;
@@ -48,6 +49,8 @@ pub trait StaticRound<Id>: 'static + Debug + Send + Sync + DynTypeId {
4849 /// The protocol this round is a part of.
4950 type Protocol : Protocol < Id > ;
5051
52+ type ProvableError : ProvableError < Id , Round = Self > ;
53+
5154 /// Returns the information about the position of this round in the state transition graph.
5255 ///
5356 /// See [`TransitionInfo`] documentation for more details.
@@ -295,3 +298,112 @@ where
295298 self . round . finalize ( rng, payloads, artifacts)
296299 }
297300}
301+
302+ /// Describes provable errors originating during protocol execution.
303+ ///
304+ /// Provable here means that we can create an evidence object entirely of messages signed by some party,
305+ /// which, in combination, prove the party's malicious actions.
306+ pub trait ProvableError < Id > : Debug + Clone + Serialize + for < ' de > Deserialize < ' de > {
307+ type Round : StaticRound < Id > ;
308+
309+ /// Specifies the messages of the guilty party that need to be stored as the evidence
310+ /// to prove its malicious behavior.
311+ fn required_previous_messages ( & self ) -> RequiredMessages ;
312+
313+ /// Returns `Ok(())` if the attached messages indeed prove that a malicious action happened.
314+ ///
315+ /// The signatures and metadata of the messages will be checked by the calling code,
316+ /// the responsibility of this method is just to check the message contents.
317+ ///
318+ /// `message` contain the message parts that triggered the error
319+ /// during [`Round::receive_message`].
320+ ///
321+ /// `previous_messages` are message parts from the previous rounds, as requested by
322+ /// [`required_messages`](Self::required_messages).
323+ ///
324+ /// Note that if some message part was not requested by above methods, it will be set to an empty one
325+ /// in the [`ProtocolMessage`], even if it was present originally.
326+ ///
327+ /// `combined_echos` are bundled echos from other parties from the previous rounds,
328+ /// as requested by [`required_messages`](Self::required_messages).
329+ fn verify_evidence (
330+ & self ,
331+ from : & Id ,
332+ shared_randomness : & [ u8 ] ,
333+ shared_data : & <<Self :: Round as StaticRound < Id > >:: Protocol as Protocol < Id > >:: SharedData ,
334+ messages : EvidenceMessages < Id , Self :: Round > ,
335+ ) -> Result < ( ) , ProtocolValidationError > ;
336+ }
337+
338+ #[ derive( Debug ) ]
339+ pub struct EvidenceMessages < Id , R : StaticRound < Id > > {
340+ message : ProtocolMessage ,
341+ previous_messages : BTreeMap < RoundId , ProtocolMessage > ,
342+ combined_echos : BTreeMap < RoundId , BTreeMap < Id , EchoBroadcast > > ,
343+ format : BoxedFormat ,
344+ phantom : PhantomData < R > ,
345+ }
346+
347+ impl < Id , R : StaticRound < Id > > EvidenceMessages < Id , R > {
348+ pub fn previous_echo_broadcast < PR : StaticRound < Id > > (
349+ & self ,
350+ round_num : u8 ,
351+ ) -> Result < PR :: EchoBroadcast , ProtocolValidationError > {
352+ Ok ( self
353+ . previous_messages
354+ . get ( & RoundId :: new ( round_num) )
355+ . unwrap ( )
356+ . echo_broadcast
357+ . deserialize :: < PR :: EchoBroadcast > ( & self . format )
358+ . unwrap ( ) )
359+ }
360+
361+ pub fn combined_echos < PR : StaticRound < Id > > (
362+ & self ,
363+ round_num : u8 ,
364+ ) -> Result < BTreeMap < Id , PR :: EchoBroadcast > , ProtocolValidationError > {
365+ todo ! ( )
366+ }
367+
368+ pub fn direct_message ( & self ) -> Result < R :: DirectMessage , ProtocolValidationError > {
369+ todo ! ( )
370+ }
371+
372+ pub ( crate ) fn into_round < NR > ( self ) -> EvidenceMessages < Id , NR >
373+ where
374+ NR : StaticRound <
375+ Id ,
376+ EchoBroadcast = R :: EchoBroadcast ,
377+ NormalBroadcast = R :: NormalBroadcast ,
378+ DirectMessage = R :: DirectMessage ,
379+ > ,
380+ {
381+ EvidenceMessages :: < Id , NR > {
382+ message : self . message ,
383+ previous_messages : self . previous_messages ,
384+ combined_echos : self . combined_echos ,
385+ format : self . format ,
386+ phantom : PhantomData ,
387+ }
388+ }
389+ }
390+
391+ #[ derive_where:: derive_where( Clone ) ]
392+ #[ derive( Debug , Copy , Serialize , Deserialize ) ]
393+ pub struct NoProvableErrors < R > ( PhantomData < R > ) ;
394+
395+ impl < Id : PartyId , R : StaticRound < Id > > ProvableError < Id > for NoProvableErrors < R > {
396+ type Round = R ;
397+ fn required_previous_messages ( & self ) -> RequiredMessages {
398+ unimplemented ! ( )
399+ }
400+ fn verify_evidence (
401+ & self ,
402+ from : & Id ,
403+ shared_randomness : & [ u8 ] ,
404+ shared_data : & <<Self :: Round as StaticRound < Id > >:: Protocol as Protocol < Id > >:: SharedData ,
405+ messages : EvidenceMessages < Id , Self :: Round > ,
406+ ) -> Result < ( ) , ProtocolValidationError > {
407+ unimplemented ! ( )
408+ }
409+ }
0 commit comments