github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/types.go (about)

     1  // Copyright 2020 The go-simplechain Authors
     2  // This file is part of the go-simplechain library.
     3  //
     4  // The go-simplechain 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-simplechain 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-simplechain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package pbft
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"math/big"
    23  
    24  	"github.com/bigzoro/my_simplechain/common"
    25  	"github.com/bigzoro/my_simplechain/core/types"
    26  	"github.com/bigzoro/my_simplechain/rlp"
    27  )
    28  
    29  // Proposal supports retrieving height and serialized block to be used during Istanbul consensus.
    30  type Proposal interface {
    31  	// Number retrieves the sequence number of this proposal.
    32  	Number() *big.Int
    33  
    34  	PendingHash() common.Hash // unexecuted block hash
    35  
    36  	EncodeRLP(w io.Writer) error
    37  
    38  	DecodeRLP(s *rlp.Stream) error
    39  
    40  	String() string
    41  
    42  	FetchMissedTxs(misses []types.MissedTx) (types.Transactions, error)
    43  
    44  	IsEmpty() bool
    45  }
    46  
    47  // Conclusion means executed Proposal
    48  type Conclusion interface {
    49  	Proposal
    50  	// Hash retrieves the hash of this proposal.
    51  	Hash() common.Hash
    52  }
    53  
    54  // LightProposal is a Proposal without tx body
    55  type LightProposal interface {
    56  	Proposal
    57  
    58  	TxDigests() []common.Hash
    59  
    60  	Completed() bool // return whether the proposal is completed (no missed txs)
    61  
    62  	FillMissedTxs(txs types.Transactions) error
    63  }
    64  
    65  type Request struct {
    66  	Proposal Proposal // always common proposal (block with all txs)
    67  }
    68  
    69  func (r *Request) TerminalString() string {
    70  	if r == nil {
    71  		return "nil"
    72  	}
    73  	return fmt.Sprintf("hash: %s, number: %d", r.Proposal.PendingHash().TerminalString(), r.Proposal.Number())
    74  }
    75  
    76  // View includes a round number and a sequence number.
    77  // Sequence is the block number we'd like to commit.
    78  // Each round has a number and is composed by 3 steps: preprepare, prepare and commit.
    79  //
    80  // If the given block is not accepted by validators, a round change will occur
    81  // and the validators start a new round with round+1.
    82  type View struct {
    83  	Round    *big.Int
    84  	Sequence *big.Int
    85  }
    86  
    87  // EncodeRLP serializes b into the Ethereum RLP format.
    88  func (v *View) EncodeRLP(w io.Writer) error {
    89  	return rlp.Encode(w, []interface{}{v.Round, v.Sequence})
    90  }
    91  
    92  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
    93  func (v *View) DecodeRLP(s *rlp.Stream) error {
    94  	var view struct {
    95  		Round    *big.Int
    96  		Sequence *big.Int
    97  	}
    98  
    99  	if err := s.Decode(&view); err != nil {
   100  		return err
   101  	}
   102  	v.Round, v.Sequence = view.Round, view.Sequence
   103  	return nil
   104  }
   105  
   106  func (v *View) String() string {
   107  	return fmt.Sprintf("{Round: %d, Sequence: %d}", v.Round.Uint64(), v.Sequence.Uint64())
   108  }
   109  
   110  // Cmp compares v and y and returns:
   111  //
   112  //	-1 if v <  y
   113  //	 0 if v == y
   114  //	+1 if v >  y
   115  func (v *View) Cmp(y *View) int {
   116  	if v.Sequence.Cmp(y.Sequence) != 0 {
   117  		return v.Sequence.Cmp(y.Sequence)
   118  	}
   119  	if v.Round.Cmp(y.Round) != 0 {
   120  		return v.Round.Cmp(y.Round)
   121  	}
   122  	return 0
   123  }
   124  
   125  type Preprepare struct {
   126  	View     *View
   127  	Proposal Proposal
   128  }
   129  
   130  // EncodeRLP serializes b into the Ethereum RLP format.
   131  func (b *Preprepare) EncodeRLP(w io.Writer) error {
   132  	return rlp.Encode(w, []interface{}{b.View, b.Proposal})
   133  }
   134  
   135  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
   136  func (b *Preprepare) DecodeRLP(s *rlp.Stream) error {
   137  	var preprepare struct {
   138  		View     *View
   139  		Proposal *types.Block
   140  	}
   141  
   142  	if err := s.Decode(&preprepare); err != nil {
   143  		return err
   144  	}
   145  	b.View, b.Proposal = preprepare.View, preprepare.Proposal
   146  
   147  	return nil
   148  }
   149  
   150  type LightPreprepare Preprepare
   151  
   152  func (b *LightPreprepare) FullPreprepare() *Preprepare {
   153  	return &Preprepare{
   154  		View:     b.View,
   155  		Proposal: Light2Proposal(b.Proposal),
   156  	}
   157  }
   158  
   159  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
   160  // Overwrite Decode method for light block
   161  func (b *LightPreprepare) DecodeRLP(s *rlp.Stream) error {
   162  	var preprepare struct {
   163  		View     *View
   164  		Proposal *types.LightBlock
   165  	}
   166  
   167  	if err := s.Decode(&preprepare); err != nil {
   168  		return err
   169  	}
   170  	b.View, b.Proposal = preprepare.View, preprepare.Proposal
   171  
   172  	return nil
   173  }
   174  
   175  type Subject struct {
   176  	View    *View
   177  	Pending common.Hash
   178  	Digest  common.Hash
   179  }
   180  
   181  // EncodeRLP serializes b into the Ethereum RLP format.
   182  func (b *Subject) EncodeRLP(w io.Writer) error {
   183  	return rlp.Encode(w, []interface{}{b.View, b.Pending, b.Digest})
   184  }
   185  
   186  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
   187  func (b *Subject) DecodeRLP(s *rlp.Stream) error {
   188  	var subject struct {
   189  		View    *View
   190  		Pending common.Hash
   191  		Digest  common.Hash
   192  	}
   193  
   194  	if err := s.Decode(&subject); err != nil {
   195  		return err
   196  	}
   197  	b.View, b.Pending, b.Digest = subject.View, subject.Pending, subject.Digest
   198  	return nil
   199  }
   200  
   201  func (b *Subject) String() string {
   202  	return fmt.Sprintf("{View: %v, Pending:%v, Digest: %v}", b.View, b.Pending.String(), b.Digest.String())
   203  }
   204  
   205  type MissedReq struct {
   206  	View      *View
   207  	MissedTxs []types.MissedTx
   208  }
   209  
   210  func (b *MissedReq) String() string {
   211  	return fmt.Sprintf("{View: %v, Missed:%v}", b.View, len(b.MissedTxs))
   212  
   213  }
   214  
   215  func (b *MissedReq) EncodeRLP(w io.Writer) error {
   216  	return rlp.Encode(w, []interface{}{b.View, b.MissedTxs})
   217  }
   218  
   219  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
   220  func (b *MissedReq) DecodeRLP(s *rlp.Stream) error {
   221  	var subject struct {
   222  		View      *View
   223  		MissedReq []types.MissedTx
   224  	}
   225  
   226  	if err := s.Decode(&subject); err != nil {
   227  		return err
   228  	}
   229  	b.View, b.MissedTxs = subject.View, subject.MissedReq
   230  	return nil
   231  }
   232  
   233  type MissedResp struct {
   234  	View   *View
   235  	ReqTxs types.Transactions
   236  }
   237  
   238  func (b *MissedResp) EncodeRLP(w io.Writer) error {
   239  	return rlp.Encode(w, []interface{}{b.View, b.ReqTxs})
   240  }
   241  
   242  // DecodeRLP implements rlp.Decoder, and load the consensus fields from a RLP stream.
   243  func (b *MissedResp) DecodeRLP(s *rlp.Stream) error {
   244  	var subject struct {
   245  		View   *View
   246  		ReqTxs types.Transactions
   247  	}
   248  
   249  	if err := s.Decode(&subject); err != nil {
   250  		return err
   251  	}
   252  	b.View, b.ReqTxs = subject.View, subject.ReqTxs
   253  	return nil
   254  }
   255  
   256  var offsetCodec = &types.OffsetTransactionsCodec{}
   257  
   258  func (b *MissedResp) EncodeOffset() ([]byte, error) {
   259  	encTxs, err := offsetCodec.EncodeToBytes(b.ReqTxs)
   260  	if err != nil {
   261  		return nil, err
   262  	}
   263  	encView, err := rlp.EncodeToBytes(b.View)
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	return append(encTxs, encView...), nil
   268  }
   269  
   270  func (b *MissedResp) DecodeOffset(buf []byte) error {
   271  	var txs = new(types.Transactions)
   272  	n, err := offsetCodec.DecodeBytes(buf, txs)
   273  	if err != nil {
   274  		return err
   275  	}
   276  	if n >= len(buf)-1 {
   277  		return fmt.Errorf("view info missed")
   278  	}
   279  	var view View
   280  	err = rlp.DecodeBytes(buf[n:], &view)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	b.View, b.ReqTxs = &view, *txs
   285  	return nil
   286  }
   287  
   288  // Proposal2Light change the common proposal to the light proposal
   289  // return nil if proposal to block failed
   290  func Proposal2Light(proposal Proposal, init bool) LightProposal {
   291  	block, ok := proposal.(*types.Block)
   292  	if !ok {
   293  		return nil
   294  	}
   295  	if !init {
   296  		return &types.LightBlock{Block: *block}
   297  	}
   298  	return types.NewLightBlock(block)
   299  }
   300  
   301  // Light2Proposal trans a light proposal to the common proposal
   302  // warning: will panic if proposal is not light
   303  func Light2Proposal(proposal Proposal) Proposal {
   304  	return &proposal.(*types.LightBlock).Block
   305  }