github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/core/preprepare_test.go (about)

     1  // Copyright 2017 AMIS Technologies
     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  	"github.com/ethereum/go-ethereum/log"
    21  	//"github.com/ethereum/go-ethereum/log"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/ethereum/go-ethereum/consensus/podc"
    27  )
    28  
    29  func newTestPreprepare(v *podc.View) *podc.Preprepare {
    30  	return &podc.Preprepare{
    31  		View:     v,
    32  		Proposal: newTestProposal(),
    33  	}
    34  }
    35  
    36  func TestHandlePreprepare(t *testing.T) {
    37  	N := uint64(20) // replica 0 is primary, it will send messages to others
    38  	F := uint64(1) // F does not affect tests
    39  
    40  	testCases := []struct {
    41  		system          *testSystem
    42  		expectedRequest podc.Proposal
    43  		expectedErr     error
    44  	}{
    45  		{
    46  			// normal case
    47  			func() *testSystem {
    48  				sys := NewTestSystemWithBackend(N, F)
    49  
    50  				for i, backend := range sys.backends {
    51  					c := backend.engine.(*core)
    52  					c.valSet = backend.peers
    53  					if i != 0 {
    54  						c.state = StateAcceptRequest
    55  					}
    56  				}
    57  				return sys
    58  			}(),
    59  			newTestProposal(),
    60  			nil,
    61  		},
    62  		{
    63  			// future message
    64  			func() *testSystem {
    65  				sys := NewTestSystemWithBackend(N, F)
    66  
    67  				for i, backend := range sys.backends {
    68  					c := backend.engine.(*core)
    69  					c.valSet = backend.peers
    70  					if i != 0 {
    71  						c.state = StateAcceptRequest
    72  						// hack: force set subject that future message can be simulated
    73  						c.current = newTestRoundState(
    74  							&podc.View{
    75  								Round:    big.NewInt(0),
    76  								Sequence: big.NewInt(0),
    77  							},
    78  							c.valSet,
    79  						)
    80  
    81  					} else {
    82  						c.current.SetSequence(big.NewInt(10))
    83  					}
    84  				}
    85  				return sys
    86  			}(),
    87  			makeBlock(1),
    88  			errFutureMessage,
    89  		},
    90  		{
    91  			// non-proposer
    92  			func() *testSystem {
    93  				sys := NewTestSystemWithBackend(N, F)
    94  
    95  				// force remove replica 0, let replica 1 become primary
    96  				sys.backends = sys.backends[1:]
    97  
    98  				for i, backend := range sys.backends {
    99  					c := backend.engine.(*core)
   100  					c.valSet = backend.peers
   101  					if i != 0 {
   102  						// replica 0 is primary
   103  						c.state = StatePreprepared
   104  					}
   105  				}
   106  				return sys
   107  			}(),
   108  			makeBlock(1),
   109  			errNotFromProposer,
   110  		},
   111  		{
   112  			// ErrInvalidMessage
   113  			func() *testSystem {
   114  				sys := NewTestSystemWithBackend(N, F)
   115  
   116  				for i, backend := range sys.backends {
   117  					c := backend.engine.(*core)
   118  					c.valSet = backend.peers
   119  					if i != 0 {
   120  						c.state = StatePreprepared
   121  						c.current.SetSequence(big.NewInt(10))
   122  						c.current.SetRound(big.NewInt(10))
   123  					}
   124  				}
   125  				return sys
   126  			}(),
   127  			makeBlock(1),
   128  			errOldMessage,
   129  		},
   130  	}
   131  
   132  OUTER:
   133  	for _, test := range testCases {
   134  		test.system.Run(false)
   135  
   136  		v0 := test.system.backends[0]
   137  		r0 := v0.engine.(*core)
   138  
   139  		curView := r0.currentView()
   140  
   141  		preprepare := &podc.Preprepare{
   142  			View:     curView,
   143  			Proposal: test.expectedRequest,
   144  		}
   145  
   146  		for i, v := range test.system.backends {
   147  			// i == 0 is primary backend, it is responsible for send preprepare messages to others.
   148  			if i == 0 {
   149  				continue
   150  			}
   151  
   152  			c := v.engine.(*core)
   153  
   154  			m, _ := Encode(preprepare)
   155  			_, val := r0.valSet.GetByAddress(v0.Address())
   156  			// run each backends and verify handlePreprepare function.
   157  			log.Info("Address", "Address", v0.Address() )
   158  			if err := c.handlePreprepare(&message{
   159  				Code:    msgPreprepare,
   160  				Msg:     m,
   161  				Address: v0.Address(),
   162  			}, val); err != nil {
   163  				if err != test.expectedErr {
   164  					t.Errorf("error mismatch: have %v, want %v", err, test.expectedErr)
   165  				}
   166  				continue OUTER
   167  			}
   168  
   169  			if c.state != StatePreprepared {
   170  				t.Errorf("state mismatch: have %v, want %v", c.state, StatePreprepared)
   171  			}
   172  
   173  			if !reflect.DeepEqual(c.current.Subject().View, curView) {
   174  				t.Errorf("view mismatch: have %v, want %v", c.current.Subject().View, curView)
   175  			}
   176  
   177  			// verify prepare messages
   178  			//log.Info("message=", "message",message)
   179  			//testmsg := &message{
   180  			//	Code:    msgPreprepare,
   181  			//	Msg:     m,
   182  			//	Address: v0.Address(),
   183  			//}
   184  			decodedMsg := new(message)
   185  			err := decodedMsg.FromPayload(v.sentMsgs[0], nil)
   186  			if err != nil {
   187  				t.Errorf("error mismatch: have %v, want nil", err)
   188  			}
   189  
   190  			if decodedMsg.Code != msgDSelect {
   191  				t.Errorf("message code mismatch: have %v, want %v", decodedMsg.Code, msgDSelect)
   192  			}
   193  			var subject *podc.Subject
   194  			err = decodedMsg.Decode(&subject)
   195  			if err != nil {
   196  				t.Errorf("error mismatch: have %v, want nil", err)
   197  			}
   198  			if !reflect.DeepEqual(subject, c.current.Subject()) {
   199  				t.Errorf("subject mismatch: have %v, want %v", subject, c.current.Subject())
   200  			}
   201  		}
   202  	}
   203  }