github.com/electroneum/electroneum-sc@v0.0.0-20230105223411-3bc1d078281e/consensus/istanbul/core/qbft_msg_set.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"math/big"
    23  	"strings"
    24  	"sync"
    25  
    26  	"github.com/electroneum/electroneum-sc/common"
    27  	"github.com/electroneum/electroneum-sc/consensus/istanbul"
    28  	qbfttypes "github.com/electroneum/electroneum-sc/consensus/istanbul/types"
    29  	"github.com/electroneum/electroneum-sc/rlp"
    30  )
    31  
    32  // Construct a new message set to accumulate messages for given sequence/view number.
    33  func newQBFTMsgSet(valSet istanbul.ValidatorSet) *qbftMsgSet {
    34  	return &qbftMsgSet{
    35  		view: &istanbul.View{
    36  			Round:    new(big.Int),
    37  			Sequence: new(big.Int),
    38  		},
    39  		messagesMu: new(sync.Mutex),
    40  		messages:   make(map[common.Address]qbfttypes.QBFTMessage),
    41  		valSet:     valSet,
    42  	}
    43  }
    44  
    45  // ----------------------------------------------------------------------------
    46  
    47  type qbftMsgSet struct {
    48  	view       *istanbul.View
    49  	valSet     istanbul.ValidatorSet
    50  	messagesMu *sync.Mutex
    51  	messages   map[common.Address]qbfttypes.QBFTMessage
    52  }
    53  
    54  // qbftMsgMapAsStruct is a temporary holder struct to convert messages map to a slice when Encoding and Decoding qbftMsgSet
    55  type qbftMsgMapAsStruct struct {
    56  	Address common.Address
    57  	Msg     qbfttypes.QBFTMessage
    58  }
    59  
    60  func (ms *qbftMsgSet) View() *istanbul.View {
    61  	return ms.view
    62  }
    63  
    64  func (ms *qbftMsgSet) Add(msg qbfttypes.QBFTMessage) error {
    65  	ms.messagesMu.Lock()
    66  	defer ms.messagesMu.Unlock()
    67  	ms.messages[msg.Source()] = msg
    68  	return nil
    69  }
    70  
    71  func (ms *qbftMsgSet) Values() (result []qbfttypes.QBFTMessage) {
    72  	ms.messagesMu.Lock()
    73  	defer ms.messagesMu.Unlock()
    74  
    75  	for _, v := range ms.messages {
    76  		result = append(result, v)
    77  	}
    78  
    79  	return result
    80  }
    81  
    82  func (ms *qbftMsgSet) Size() int {
    83  	ms.messagesMu.Lock()
    84  	defer ms.messagesMu.Unlock()
    85  	return len(ms.messages)
    86  }
    87  
    88  func (ms *qbftMsgSet) Get(addr common.Address) qbfttypes.QBFTMessage {
    89  	ms.messagesMu.Lock()
    90  	defer ms.messagesMu.Unlock()
    91  	return ms.messages[addr]
    92  }
    93  
    94  // ----------------------------------------------------------------------------
    95  
    96  func (ms *qbftMsgSet) String() string {
    97  	ms.messagesMu.Lock()
    98  	defer ms.messagesMu.Unlock()
    99  	addresses := make([]string, 0, len(ms.messages))
   100  	for _, v := range ms.messages {
   101  		addresses = append(addresses, v.Source().String())
   102  	}
   103  	return fmt.Sprintf("[%v]", strings.Join(addresses, ", "))
   104  }
   105  
   106  // EncodeRLP serializes qbftMsgSet into Ethereum RLP format
   107  // valSet is currently not being encoded.
   108  func (ms *qbftMsgSet) EncodeRLP(w io.Writer) error {
   109  	if ms == nil {
   110  		return nil
   111  	}
   112  	ms.messagesMu.Lock()
   113  	defer ms.messagesMu.Unlock()
   114  
   115  	// maps cannot be RLP encoded, convert the map into a slice of struct and then encode it
   116  	var messagesAsSlice []qbftMsgMapAsStruct
   117  	for k, v := range ms.messages {
   118  		msgMapAsStruct := qbftMsgMapAsStruct{
   119  			Address: k,
   120  			Msg:     v,
   121  		}
   122  		messagesAsSlice = append(messagesAsSlice, msgMapAsStruct)
   123  	}
   124  
   125  	return rlp.Encode(w, []interface{}{
   126  		ms.view,
   127  		messagesAsSlice,
   128  	})
   129  }
   130  
   131  // DecodeRLP deserializes rlp stream into qbftMsgSet
   132  // valSet is currently not being decoded
   133  func (ms *qbftMsgSet) DecodeRLP(stream *rlp.Stream) error {
   134  	// Don't decode qbftMsgSet if the size of the stream is 0
   135  	_, size, _ := stream.Kind()
   136  	if size == 0 {
   137  		return nil
   138  	}
   139  	var msgSet struct {
   140  		MsgView *istanbul.View
   141  		//		valSet        istanbul.ValidatorSet
   142  		MessagesSlice []qbftMsgMapAsStruct
   143  	}
   144  	if err := stream.Decode(&msgSet); err != nil {
   145  		return err
   146  	}
   147  
   148  	// convert the messages struct slice back to map
   149  	messages := make(map[common.Address]qbfttypes.QBFTMessage)
   150  	for _, msgStruct := range msgSet.MessagesSlice {
   151  		messages[msgStruct.Address] = msgStruct.Msg
   152  	}
   153  
   154  	ms.view = msgSet.MsgView
   155  	//	ms.valSet = msgSet.valSet
   156  	ms.messages = messages
   157  	ms.messagesMu = new(sync.Mutex)
   158  
   159  	return nil
   160  }