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

     1  package qbfttypes
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"math/big"
     8  
     9  	"github.com/electroneum/electroneum-sc/common"
    10  	"github.com/electroneum/electroneum-sc/consensus/istanbul"
    11  	istanbulcommon "github.com/electroneum/electroneum-sc/consensus/istanbul/common"
    12  	"github.com/electroneum/electroneum-sc/core/types"
    13  	"github.com/electroneum/electroneum-sc/log"
    14  	"github.com/electroneum/electroneum-sc/rlp"
    15  )
    16  
    17  // ROUND-CHANGE
    18  type RoundChange struct {
    19  	SignedRoundChangePayload
    20  	PreparedBlock *types.Block
    21  	Justification []*Prepare
    22  }
    23  
    24  func NewRoundChange(sequence *big.Int, round *big.Int, preparedRound *big.Int, preparedBlock istanbul.Proposal, hasBadProposal bool) *RoundChange {
    25  	roundChange := &RoundChange{
    26  		SignedRoundChangePayload: SignedRoundChangePayload{
    27  			CommonPayload: CommonPayload{
    28  				code:     RoundChangeCode,
    29  				Sequence: sequence,
    30  				Round:    round,
    31  			},
    32  			PreparedRound:  preparedRound,
    33  			PreparedDigest: common.Hash{},
    34  		},
    35  	}
    36  
    37  	if preparedBlock != nil {
    38  		roundChange.PreparedBlock = preparedBlock.(*types.Block)
    39  		roundChange.PreparedDigest = preparedBlock.Hash()
    40  		roundChange.HasBadProposal = hasBadProposal
    41  	}
    42  
    43  	return roundChange
    44  }
    45  
    46  type SignedRoundChangePayload struct {
    47  	CommonPayload
    48  	PreparedRound  *big.Int
    49  	PreparedDigest common.Hash
    50  	HasBadProposal bool
    51  }
    52  
    53  func (p *SignedRoundChangePayload) String() string {
    54  	return fmt.Sprintf("RoundChange {seq=%v, round=%v, pr=%v, pv=%v, hasBadProposal=%v}",
    55  		p.Sequence, p.Round, p.PreparedRound, p.PreparedDigest.Hex(), p.HasBadProposal)
    56  }
    57  
    58  func (p *SignedRoundChangePayload) EncodeRLP(w io.Writer) error {
    59  	var encodedPayload rlp.RawValue
    60  	encodedPayload, err := p.encodePayloadInternal()
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	return rlp.Encode(
    66  		w,
    67  		[]interface{}{encodedPayload, p.signature})
    68  }
    69  
    70  func (p *SignedRoundChangePayload) DecodeRLP(stream *rlp.Stream) error {
    71  	// Signed Payload
    72  	if _, err := stream.List(); err != nil {
    73  		log.Error("IBFT: Error List() Signed Payload", "err", err)
    74  		return err
    75  	}
    76  
    77  	// Payload
    78  	encodedPayload, err := stream.Raw()
    79  	if err != nil {
    80  		log.Error("IBFT: Error Raw()", "err", err)
    81  		return err
    82  	}
    83  
    84  	payloadStream := rlp.NewStream(bytes.NewReader(encodedPayload), 0)
    85  
    86  	if _, err = payloadStream.List(); err != nil {
    87  		log.Error("IBFT: Error List() Payload", "err", err)
    88  		return err
    89  	}
    90  
    91  	if err = payloadStream.Decode(&p.Sequence); err != nil {
    92  		log.Error("IBFT: Error Decode(&m.Sequence)", "err", err)
    93  		return err
    94  	}
    95  	if err = payloadStream.Decode(&p.Round); err != nil {
    96  		log.Error("IBFT: Error Decode(&m.Round)", "err", err)
    97  		return err
    98  	}
    99  
   100  	// Prepared
   101  	var size uint64
   102  	if size, err = payloadStream.List(); err != nil {
   103  		log.Error("IBFT: Error List() Prepared", "err", err)
   104  		return err
   105  	}
   106  	if size > 0 {
   107  		if err = payloadStream.Decode(&p.PreparedRound); err != nil {
   108  			log.Error("IBFT: Error Decode(&m.PreparedRound)", "err", err)
   109  			return err
   110  		}
   111  		if err = payloadStream.Decode(&p.PreparedDigest); err != nil {
   112  			log.Error("IBFT: Error Decode(&p.PreparedDigest)", "err", err)
   113  			return err
   114  		}
   115  		if err = payloadStream.Decode(&p.HasBadProposal); err != nil {
   116  			log.Error("IBFT: Error Decode(&p.HasBadProposal)", "err", err)
   117  			return err
   118  		}
   119  	}
   120  	// End Prepared
   121  	if err = payloadStream.ListEnd(); err != nil {
   122  		return err
   123  	}
   124  
   125  	// End Payload
   126  	if err = payloadStream.ListEnd(); err != nil {
   127  		return err
   128  	}
   129  
   130  	if err = stream.Decode(&p.signature); err != nil {
   131  		return err
   132  	}
   133  	// End SignedPayload
   134  	if err = stream.ListEnd(); err != nil {
   135  		return err
   136  	}
   137  
   138  	p.code = RoundChangeCode
   139  
   140  	log.Info("IBFT: Correctly decoded SignedRoundChangePayload", "p", p)
   141  
   142  	return nil
   143  }
   144  
   145  func (p *SignedRoundChangePayload) encodePayloadInternal() ([]byte, error) {
   146  	var prepared = []interface{}{}
   147  	if p.PreparedRound != nil && !common.EmptyHash(p.PreparedDigest) {
   148  		prepared = []interface{}{p.PreparedRound, p.PreparedDigest, p.HasBadProposal}
   149  	}
   150  	return rlp.EncodeToBytes(
   151  		[]interface{}{
   152  			p.Sequence,
   153  			p.Round,
   154  			prepared})
   155  }
   156  
   157  func (p *SignedRoundChangePayload) EncodePayloadForSigning() ([]byte, error) {
   158  	var encodedPayload rlp.RawValue
   159  	encodedPayload, err := p.encodePayloadInternal()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return rlp.EncodeToBytes(
   165  		[]interface{}{
   166  			p.Code(),
   167  			encodedPayload,
   168  		})
   169  }
   170  
   171  func (m *RoundChange) EncodeRLP(w io.Writer) error {
   172  	var encodedPayload rlp.RawValue
   173  	encodedPayload, err := m.encodePayloadInternal()
   174  	if err != nil {
   175  		return err
   176  	}
   177  
   178  	return rlp.Encode(
   179  		w,
   180  		[]interface{}{
   181  			[]interface{}{
   182  				encodedPayload,
   183  				m.signature,
   184  			},
   185  			m.PreparedBlock, m.Justification,
   186  		})
   187  }
   188  
   189  func (m *RoundChange) DecodeRLP(stream *rlp.Stream) error {
   190  	var err error
   191  
   192  	// RoundChange Message
   193  	if _, err = stream.List(); err != nil {
   194  		return err
   195  	}
   196  
   197  	// Signed Payload
   198  	if _, err = stream.List(); err != nil {
   199  		log.Error("IBFT: Error List() Signed Payload", "err", err)
   200  		return err
   201  	}
   202  
   203  	// Payload
   204  	encodedPayload, err := stream.Raw()
   205  	if err != nil {
   206  		log.Error("IBFT: Error Raw()", "err", err)
   207  		return err
   208  	}
   209  
   210  	payloadStream := rlp.NewStream(bytes.NewReader(encodedPayload), 0)
   211  
   212  	if _, err = payloadStream.List(); err != nil {
   213  		log.Error("IBFT: Error List() Payload", "err", err)
   214  		return err
   215  	}
   216  
   217  	if err = payloadStream.Decode(&m.Sequence); err != nil {
   218  		log.Error("IBFT: Error Decode(&m.Sequence)", "err", err)
   219  		return err
   220  	}
   221  	if err = payloadStream.Decode(&m.Round); err != nil {
   222  		log.Error("IBFT: Error Decode(&m.Round)", "err", err)
   223  		return err
   224  	}
   225  
   226  	// Prepared
   227  	var size uint64
   228  	if size, err = payloadStream.List(); err != nil {
   229  		log.Error("IBFT: Error List() Prepared", "err", err)
   230  		return err
   231  	}
   232  	if size > 0 {
   233  		if err = payloadStream.Decode(&m.PreparedRound); err != nil {
   234  			log.Error("IBFT: Error Decode(&m.PreparedRound)", "err", err)
   235  			return err
   236  		}
   237  		if err = payloadStream.Decode(&m.PreparedDigest); err != nil {
   238  			log.Error("IBFT: Error Decode(&m.PreparedDigest)", "err", err)
   239  			return err
   240  		}
   241  		if err = payloadStream.Decode(&m.HasBadProposal); err != nil {
   242  			log.Error("IBFT: Error Decode(&m.HasBadProposal)", "err", err)
   243  			return err
   244  		}
   245  	}
   246  	// End Prepared
   247  	if err = payloadStream.ListEnd(); err != nil {
   248  		return err
   249  	}
   250  
   251  	// End Payload
   252  	if err = payloadStream.ListEnd(); err != nil {
   253  		return err
   254  	}
   255  
   256  	if err = stream.Decode(&m.signature); err != nil {
   257  		return err
   258  	}
   259  	// End SignedPayload
   260  	if err = stream.ListEnd(); err != nil {
   261  		return err
   262  	}
   263  
   264  	if _, size, err = stream.Kind(); err != nil {
   265  		log.Error("IBFT: Error Kind()", "err", err)
   266  		return err
   267  	}
   268  	if size == 0 {
   269  		if _, err = stream.Raw(); err != nil {
   270  			log.Error("IBFT: Error Raw()", "err", err)
   271  			return err
   272  		}
   273  	} else {
   274  		if err = stream.Decode(&m.PreparedBlock); err != nil {
   275  			log.Error("IBFT: Error Decode(&m.PreparedDigest)", "err", err)
   276  			return err
   277  		}
   278  		if m.PreparedBlock.Hash() != m.PreparedDigest {
   279  			log.Error("IBFT: Error m.PreparedDigest.Hash() != digest")
   280  			return istanbulcommon.ErrFailedDecodePreprepare
   281  		}
   282  	}
   283  
   284  	if _, size, err = stream.Kind(); err != nil {
   285  		log.Error("IBFT: Error Kind()", "err", err)
   286  		return err
   287  	}
   288  	if size == 0 {
   289  		if _, err = stream.Raw(); err != nil {
   290  			log.Error("IBFT: Error Raw()", "err", err)
   291  			return err
   292  		}
   293  	} else {
   294  		if err = stream.Decode(&m.Justification); err != nil {
   295  			log.Error("IBFT: Error Decode(&m.Justification)", "err", err)
   296  			return err
   297  		}
   298  	}
   299  
   300  	// End RoundChange Message
   301  	if err = stream.ListEnd(); err != nil {
   302  		return err
   303  	}
   304  
   305  	m.code = RoundChangeCode
   306  
   307  	return nil
   308  }