github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/consensus/pbft/core/lightprepare_test.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 core
    18  
    19  import (
    20  	"github.com/bigzoro/my_simplechain/core/types"
    21  	"github.com/bigzoro/my_simplechain/crypto"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/bigzoro/my_simplechain/consensus/pbft"
    27  )
    28  
    29  func TestHandleLightPreprepare(t *testing.T) {
    30  	N := uint64(4) // replica 0 is the proposer, it will send messages to others
    31  	F := uint64(1) // F does not affect tests
    32  
    33  	signer := types.NewEIP155Signer(big.NewInt(110))
    34  	key, _ := crypto.GenerateKey()
    35  
    36  	testCases := []struct {
    37  		system          *testSystem
    38  		expectedRequest pbft.Proposal
    39  		expectedErr     error
    40  		existingBlock   bool
    41  	}{
    42  		{
    43  			// empty proposal case
    44  			func() *testSystem {
    45  				sys := NewTestSystemWithBackend(N, F)
    46  				for i, backend := range sys.backends {
    47  					c := backend.engine.(*core)
    48  					c.valSet = backend.peers
    49  					c.config.LightMode = true
    50  					if i != 0 {
    51  						c.state = StateAcceptRequest
    52  					}
    53  				}
    54  				return sys
    55  			}(),
    56  			newTestLightProposal(),
    57  			nil,
    58  			false,
    59  		},
    60  		{
    61  			// light proposal case
    62  			func() *testSystem {
    63  				sys := NewTestSystemWithBackend(N, F)
    64  				for i, backend := range sys.backends {
    65  					c := backend.engine.(*core)
    66  					c.valSet = backend.peers
    67  					c.config.LightMode = true
    68  					if i != 0 {
    69  						c.state = StateAcceptRequest
    70  						// set empty txpool for follow node
    71  						backend.txpool = newTestSystemTxPool()
    72  					} else {
    73  						backend.txpool = newTestSystemTxPool(newTransactions(1, signer, key)...)
    74  					}
    75  				}
    76  				return sys
    77  			}(),
    78  			newTestLightProposal(newTransactions(1, signer, key)...),
    79  			nil,
    80  			false,
    81  		},
    82  	}
    83  
    84  OUTER:
    85  	for _, test := range testCases {
    86  		test.system.Run(false)
    87  
    88  		v0 := test.system.backends[0]
    89  		r0 := v0.engine.(*core)
    90  
    91  		curView := r0.currentView()
    92  
    93  		lightPrepare := &pbft.LightPreprepare{
    94  			View:     curView,
    95  			Proposal: test.expectedRequest,
    96  		}
    97  
    98  		for i, v := range test.system.backends {
    99  			if i == 0 {
   100  				continue
   101  			}
   102  
   103  			c := v.engine.(*core)
   104  
   105  			m, _ := Encode(lightPrepare)
   106  
   107  			_, val := r0.valSet.GetByAddress(v0.Address())
   108  			// run each backends and verify handleLightPrepare function.
   109  			if err := c.handleLightPrepare(&message{
   110  				Code:    msgLightPreprepare,
   111  				Msg:     m,
   112  				Address: v0.Address(),
   113  			}, val); err != nil {
   114  				if err != test.expectedErr {
   115  					t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr)
   116  				}
   117  				continue OUTER
   118  			}
   119  
   120  			if c.state != StatePreprepared {
   121  				missedResp := &pbft.MissedResp{
   122  					View:   c.currentView(),
   123  					ReqTxs: test.expectedRequest.(*types.LightBlock).Block.Transactions(),
   124  				}
   125  				encMissedResp, _ := missedResp.EncodeOffset()
   126  				msg := &message{
   127  					Code: msgMissedTxs,
   128  					Msg:  encMissedResp,
   129  				}
   130  				if err := c.handleMissedTxs(msg, val); err != nil {
   131  					t.Errorf("failed to handleMissedTxs:%v", err)
   132  				}
   133  			}
   134  
   135  			if c.state != StatePreprepared {
   136  				t.Errorf("state mismatch: have %v, want %v", c.state, StatePreprepared)
   137  			}
   138  
   139  			if !test.existingBlock && !reflect.DeepEqual(c.current.Subject().View, curView) {
   140  				t.Errorf("view mismatch: have %v, want %v", c.current.Subject().View, curView)
   141  			}
   142  
   143  			// verify prepare messages
   144  			decodedMsg := new(message)
   145  			err := decodedMsg.FromPayload(v.sentMsgs[0], nil)
   146  			if err != nil {
   147  				t.Errorf("error mismatch: have %v, want nil", err)
   148  			}
   149  
   150  			expectedCode := msgPrepare
   151  			if test.existingBlock {
   152  				expectedCode = msgCommit
   153  			}
   154  			if decodedMsg.Code != expectedCode {
   155  				t.Errorf("message code mismatch: have %v, want %v", decodedMsg.Code, expectedCode)
   156  			}
   157  
   158  			var subject *pbft.Subject
   159  			err = decodedMsg.Decode(&subject)
   160  			if err != nil {
   161  				t.Errorf("error mismatch: have %v, want nil", err)
   162  			}
   163  			if !test.existingBlock && !reflect.DeepEqual(subject, c.current.Subject()) {
   164  				t.Errorf("subject mismatch: have %v, want %v", subject, c.current.Subject())
   165  			}
   166  		}
   167  	}
   168  }