Documentation
¶
Index ¶
- type BaseRound
- type Error
- type Round
- type State
- func (s *State) Done() <-chan struct{}
- func (s *State) Err() error
- func (s *State) GetRound() Round
- func (s *State) GetRoundNumber() int
- func (s *State) HandleMessage(msg *messages.Message) error
- func (s *State) IsFinished() bool
- func (s *State) MarshalJSON() ([]byte, error)
- func (s *State) ProcessAll() []*messages.Message
- func (s *State) SetRound(round Round)
- func (s *State) UnmarshalJSON(data []byte) error
- func (s *State) WaitForError() error
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BaseRound ¶
type BaseRound struct {
// contains filtered or unexported fields
}
func (*BaseRound) MarshalJSON ¶
func (*BaseRound) UnmarshalJSON ¶
type Error ¶
Error represents an error related to the protocol execution, and requires an abort. If PartyID is 0, then it was not possible to attribute the fault to one particular party.
type Round ¶
type Round interface { // ProcessMessage takes a message and validates the contents. // It then stores the message as part of the Round's own state. // If an Error is returned then the protocol must abort. // // Round0 does not need to implement this function since it is inherited from BaseRound ProcessMessage(msg *messages.Message) *Error // GenerateMessages returns a slice of messages to be sent out at the end of this Round. // It assumes that ProcessMessage has run correctly for messages from all other parties. // At the end of this method, it is assumed that no more operations are needed for the round. // If an Error is returned then the protocol must abort. GenerateMessages() ([]*messages.Message, *Error) // NextRound returns the next round of the protocol. // This does not take into account an error having occurred. // The final round of the protocol should return nil, to indicate that the protocol is finished. NextRound() Round // AcceptedMessageTypes should return a slice containing the messages types the protocol accepts. // It is constant for all rounds and should therefore be implemented by a "base" round. AcceptedMessageTypes() []messages.MessageType // Reset is expected to zero out any sensitive data that may have been copied by the round. // It is called by State when the protocol finishes, either because of an abort or because we finish. // It only needs to be implemented in Round0 if all state is held there. Reset() // SelfID returns the ID of the round participant SelfID() party.ID // PartyIDs returns a set containing all parties participating in the round PartyIDs() party.IDSlice GetOutput() interface{} }
A Round represents the internal state of protocol from the perspective of the party. It only takes care of receiving proper messages addressed to the party, and can output messages that should be sent off.
The methods ProcessMessage, GenerateMessages and NextRound should all run in this order. Doing otherwise will most likely result in undefined behaviour.
The suggested implementation of a Round based protocol is the following:
type round0 struct { *BaseRound // other state variable for the entire protocol }
func (r *round0) Reset() {} func (r *round0) AcceptedMessageTypes() []messages.MessageType { return []messages.MessageType{...} } func (r *round0) GenerateMessages() ([]*messages.Message, *Error) { ... } func (r *round0) NextRound() Round { return &round_N-1_{r} }
For all defined rounds N=1,2,... :
type round_N_ struct { *round_N-1_ }
func (r *roundN) ProcessMessage(msg *messages.Message) *Error { ... } func (r *roundN) GenerateMessages() ([]*messages.Message, *Error) { ... } func (r *roundN) NextRound() Round { return &round_N-1_{r} }
type State ¶
type State struct { RoundData []byte // contains filtered or unexported fields }
State is a struct that manages the state for the round based protocol.
It handles the initial message reception, by storing them internally and feeding them to the the current round when all messages have been received
func (*State) Done ¶
func (s *State) Done() <-chan struct{}
Done should be called like context.Done:
select { case <-s.Done(): // other cases
func (*State) GetRoundNumber ¶
func (*State) HandleMessage ¶
HandleMessage should be called on an unmarshalled messages.Message appropriate for the protocol execution. It performs basic checks to see whether the message can be used. - Is the protocol already done - Is msg is valid for this round or a future one - Is msg for us and not from us - Is the sender a party in the protocol - Have we already received a message from the party for this round?
If all these checks pass, then the message is either stored for the current round, or put in a queue for later rounds.
Note: the properties of the messages are checked in ProcessAll. Therefore, the check here should be a quite fast.
func (*State) IsFinished ¶
IsFinished returns true if the protocol has aborted or successfully finished.
func (*State) MarshalJSON ¶
MarshalJSON implements the json.Marshaller interface.
func (*State) ProcessAll ¶
ProcessAll checks whether all messages for this round have been received. If so then all messages are fed to Round.ProcessMessage. If no error was detected, then the round is processed and new messages are generated. These messages are returned to the caller and should be processed. If all went correctly, we take the messages for the next round out of the queue, and move on to the next round.
func (*State) UnmarshalJSON ¶
func (*State) WaitForError ¶
WaitForError blocks until the protocol is done. This happens either when the protocol has finished correctly, or if an error has been detected.