func (r *RBC) handleProofRequest(senderID uint64, req *ProofRequest) error {
	if senderID != r.proposerID {
		return fmt.Errorf(
			"receiving proof from (%d) that is not from the proposing node (%d)",
			senderID, r.proposerID,
		)
	}
	if r.echoSent {
		return fmt.Errorf("received proof from (%d) more the once", senderID)
	}
	if !validateProof(req) {
		return fmt.Errorf("received invalid proof from (%d)", senderID)
	}
	r.echoSent = true
	echo := &EchoRequest{*req}
	r.messages = append(r.messages, &BroadcastMessage{echo})
	return r.handleEchoRequest(r.ID, echo)
}
When a node receives a Proof from a proposer it broadcasts the proof as an
EchoRequest to the network after validating its content.
package hbbft
import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"sort"
	"github.com/NebulousLabs/merkletree"
	"github.com/klauspost/reedsolomon"
)
type BroadcastMessage struct {
	Payload interface{}
}
type ProofRequest struct {
	RootHash []byte
	Proof         [][]byte
	Index, Leaves int
}
type EchoRequest struct {
	ProofRequest
}
type ReadyRequest struct {
	RootHash []byte
}
type proofs []ProofRequest
func (p proofs) Len() int           { return len(p) }
func (p proofs) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p proofs) Less(i, j int) bool { return p[i].Index < p[j].Index }
type RBC struct {
	Config
	proposerID uint64
	enc reedsolomon.Encoder
	recvReadys map[uint64][]byte
	recvEchos map[uint64]*EchoRequest
	numParityShards, numDataShards int
	messages []*BroadcastMessage
	echoSent, readySent, outputDecoded bool
	output []byte
	closeCh   chan struct{}
	inputCh   chan rbcInputTuple
	messageCh chan rbcMessageTuple
}
type (
	rbcMessageTuple struct {
		senderID uint64
		msg      *BroadcastMessage
		err      chan error
	}
	rbcInputResponse struct {
		messages []*BroadcastMessage
		err      error
	}
	rbcInputTuple struct {
		value    []byte
		response chan rbcInputResponse
	}
)
func NewRBC(cfg Config, proposerID uint64) *RBC {
	if cfg.F == 0 {
		cfg.F = (cfg.N - 1) / 3
	}
	var (
		parityShards = 2 * cfg.F
		dataShards   = cfg.N - parityShards
	)
	enc, err := reedsolomon.New(dataShards, parityShards)
	if err != nil {
		panic(err)
	}
	rbc := &RBC{
		Config:          cfg,
		recvEchos:       make(map[uint64]*EchoRequest),
		recvReadys:      make(map[uint64][]byte),
		enc:             enc,
		numParityShards: parityShards,
		numDataShards:   dataShards,
		messages:        []*BroadcastMessage{},
		proposerID:      proposerID,
		closeCh:         make(chan struct{}),
		inputCh:         make(chan rbcInputTuple),
		messageCh:       make(chan rbcMessageTuple),
	}
	go rbc.run()
	return rbc
}
func (r *RBC) InputValue(data []byte) ([]*BroadcastMessage, error) {
	t := rbcInputTuple{
		value:    data,
		response: make(chan rbcInputResponse),
	}
	r.inputCh <- t
	resp := <-t.response
	return resp.messages, resp.err
}
func (r *RBC) HandleMessage(senderID uint64, msg *BroadcastMessage) error {
	t := rbcMessageTuple{
		senderID: senderID,
		msg:      msg,
		err:      make(chan error),
	}
	r.messageCh <- t
	return <-t.err
}
func (r *RBC) stop() {
	close(r.closeCh)
}
func (r *RBC) run() {
	for {
		select {
		case <-r.closeCh:
			return
		case t := <-r.inputCh:
			msgs, err := r.inputValue(t.value)
			t.response <- rbcInputResponse{
				messages: msgs,
				err:      err,
			}
		case t := <-r.messageCh:
			t.err <- r.handleMessage(t.senderID, t.msg)
		}
	}
}
func (r *RBC) inputValue(data []byte) ([]*BroadcastMessage, error) {
	shards, err := makeShards(r.enc, data)
	if err != nil {
		return nil, err
	}
	reqs, err := makeBroadcastMessages(shards)
	if err != nil {
		return nil, err
	}
	proof := reqs[0].Payload.(*ProofRequest)
	if err := r.handleProofRequest(r.ID, proof); err != nil {
		return nil, err
	}
	return reqs[1:], nil
}
func (r *RBC) handleMessage(senderID uint64, msg *BroadcastMessage) error {
	switch t := msg.Payload.(type) {
	case *ProofRequest:
		return r.handleProofRequest(senderID, t)
	case *EchoRequest:
		return r.handleEchoRequest(senderID, t)
	case *ReadyRequest:
		return r.handleReadyRequest(senderID, t)
	default:
		return fmt.Errorf("invalid RBC protocol message: %+v", msg)
	}
}
func (r *RBC) Messages() []*BroadcastMessage {
	msgs := r.messages
	r.messages = []*BroadcastMessage{}
	return msgs
}
func (r *RBC) Output() []byte {
	if r.output != nil {
		out := r.output
		r.output = nil
		return out
	}
	return nil
}