github.com/reapchain/go-reapchain@v0.2.15-0.20210609012950-9735c110c705/consensus/podc/core/backlog_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  	"math/big"
    21  	"reflect"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/consensus/podc"
    28  	"github.com/ethereum/go-ethereum/consensus/podc/validator"
    29  	"github.com/ethereum/go-ethereum/event"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"gopkg.in/karalabe/cookiejar.v2/collections/prque"
    32  )
    33  
    34  func TestCheckMessage(t *testing.T) {
    35  	c := &core{
    36  		state: StateAcceptRequest,
    37  		current: newRoundState(&podc.View{
    38  			Sequence: big.NewInt(1),
    39  			Round:    big.NewInt(0),
    40  		}, newTestValidatorSet(4)),
    41  	}
    42  
    43  	// invalid view format
    44  	err := c.checkMessage(msgPreprepare, nil)
    45  	if err != errInvalidMessage {
    46  		t.Errorf("error mismatch: have %v, want %v", err, errInvalidMessage)
    47  	}
    48  
    49  	testStates := []State{StateAcceptRequest, StateRequestQman, StatePreprepared, StateDSelected, StateCommitted}
    50  	testCode := []uint64{msgPreprepare, msgDSelect, msgCommit}  //msgDSelect
    51  
    52  	// future sequence
    53  	v := &podc.View{
    54  		Sequence: big.NewInt(2),
    55  		Round:    big.NewInt(0),
    56  	}
    57  	for i := 0; i < len(testStates); i++ {
    58  		c.state = testStates[i]
    59  		for j := 0; j < len(testCode); j++ {
    60  			err := c.checkMessage(testCode[j], v)
    61  			if err != errFutureMessage {
    62  				t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
    63  			}
    64  		}
    65  	}
    66  
    67  	// future round
    68  	v = &podc.View{
    69  		Sequence: big.NewInt(1),
    70  		Round:    big.NewInt(1),
    71  	}
    72  	for i := 0; i < len(testStates); i++ {
    73  		c.state = testStates[i]
    74  		for j := 0; j < len(testCode); j++ {
    75  			err := c.checkMessage(testCode[j], v)
    76  			if err != errFutureMessage {
    77  				t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
    78  			}
    79  		}
    80  	}
    81  
    82  	// current view but waiting for round change
    83  	v = &podc.View{
    84  		Sequence: big.NewInt(1),
    85  		Round:    big.NewInt(0),
    86  	}
    87  	c.waitingForRoundChange = true
    88  	for i := 0; i < len(testStates); i++ {
    89  		c.state = testStates[i]
    90  		for j := 0; j < len(testCode); j++ {
    91  			err := c.checkMessage(testCode[j], v)
    92  			if err != errFutureMessage {
    93  				t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
    94  			}
    95  		}
    96  	}
    97  	c.waitingForRoundChange = false
    98  
    99  	v = c.currentView()
   100  	// current view, state = StateAcceptRequest
   101  	c.state = StateAcceptRequest
   102  	for i := 0; i < len(testCode); i++ {
   103  		err = c.checkMessage(testCode[i], v)
   104  		if testCode[i] == msgPreprepare {
   105  			if err != nil {
   106  				t.Errorf("error mismatch: have %v, want nil", err)
   107  			}
   108  		} else {
   109  			if err != errFutureMessage {
   110  				//yicho  temp: t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
   111  			}
   112  		}
   113  	}
   114  
   115  	// current view, state = StatePreprepared
   116  	c.state = StatePreprepared
   117  	for i := 0; i < len(testCode); i++ {
   118  		err = c.checkMessage(testCode[i], v)
   119  		if err != nil {
   120  			t.Errorf("error mismatch: have %v, want nil", err)
   121  		}
   122  	}
   123  
   124  	// current view, state = StatePrepared
   125  	c.state = StateDSelected  //StatePrepared
   126  	for i := 0; i < len(testCode); i++ {
   127  		err = c.checkMessage(testCode[i], v)
   128  		if err != nil {
   129  			t.Errorf("error mismatch: have %v, want nil", err)
   130  		}
   131  	}
   132  
   133  	// current view, state = StateCommitted
   134  	c.state = StateDCommitted
   135  	for i := 0; i < len(testCode); i++ {
   136  		err = c.checkMessage(testCode[i], v)
   137  		if err != nil {
   138  			t.Errorf("error mismatch: have %v, want nil", err)
   139  		}
   140  	}
   141  
   142  }
   143  
   144  func TestStoreBacklog(t *testing.T) {
   145  	c := &core{
   146  		logger:     log.New("backend", "test", "id", 0),
   147  		backlogs:   make(map[podc.Validator]*prque.Prque),
   148  		backlogsMu: new(sync.Mutex),
   149  	}
   150  	v := &podc.View{
   151  		Round:    big.NewInt(10),
   152  		Sequence: big.NewInt(10),
   153  	}
   154  	p := validator.New(common.StringToAddress("12345667890"))
   155  	// push preprepare msg
   156  	preprepare := &podc.Preprepare{
   157  		View:     v,
   158  		Proposal: makeBlock(1),
   159  	}
   160  	prepreparePayload, _ := Encode(preprepare)
   161  	m := &message{
   162  		Code: msgPreprepare,
   163  		Msg:  prepreparePayload,
   164  	}
   165  	c.storeBacklog(m, p)
   166  	msg := c.backlogs[p].PopItem()
   167  	if !reflect.DeepEqual(msg, m) {
   168  		t.Errorf("message mismatch: have %v, want %v", msg, m)
   169  	}
   170  
   171  	// push prepare msg
   172  	subject := &podc.Subject{
   173  		View:   v,
   174  		Digest: common.StringToHash("1234567890"),
   175  	}
   176  	subjectPayload, _ := Encode(subject)
   177  
   178  	m = &message{
   179  		Code: msgDSelect,
   180  		Msg:  subjectPayload,
   181  	}
   182  	c.storeBacklog(m, p)
   183  	msg = c.backlogs[p].PopItem()
   184  	if !reflect.DeepEqual(msg, m) {
   185  		t.Errorf("message mismatch: have %v, want %v", msg, m)
   186  	}
   187  
   188  	// push commit msg
   189  	m = &message{
   190  		Code: msgDCommit,
   191  		Msg:  subjectPayload,
   192  	}
   193  	c.storeBacklog(m, p)
   194  	msg = c.backlogs[p].PopItem()
   195  	if !reflect.DeepEqual(msg, m) {
   196  		t.Errorf("message mismatch: have %v, want %v", msg, m)
   197  	}
   198  }
   199  
   200  func TestProcessFutureBacklog(t *testing.T) {
   201  	backend := &testSystemBackend{
   202  		events: new(event.TypeMux),
   203  	}
   204  	var c = &core{
   205  		logger:     log.New("backend", "test", "id", 0),
   206  		backlogs:   make(map[podc.Validator]*prque.Prque),
   207  		backlogsMu: new(sync.Mutex),
   208  		backend:    backend, //podc.Backend
   209  		current: newRoundState(&podc.View{
   210  			Sequence: big.NewInt(1),
   211  			Round:    big.NewInt(0),
   212  		}, newTestValidatorSet(4)),
   213  		state: StateAcceptRequest,
   214  	}
   215  	c.subscribeEvents()
   216  	defer c.unsubscribeEvents()
   217  
   218  	v := &podc.View{
   219  		Round:    big.NewInt(10),
   220  		Sequence: big.NewInt(10),
   221  	}
   222  	p := validator.New(common.StringToAddress("12345667890"))
   223  	// push a future msg
   224  	subject := &podc.Subject{
   225  		View:   v,
   226  		Digest: common.StringToHash("1234567890"),
   227  	}
   228  	subjectPayload, _ := Encode(subject)
   229  	m := &message{
   230  		Code: msgDCommit,
   231  		Msg:  subjectPayload,
   232  	}
   233  	c.storeBacklog(m, p)
   234  	c.processBacklog()
   235  
   236  	const timeoutDura = 2 * time.Second
   237  	timeout := time.NewTimer(timeoutDura)
   238  	select {
   239  	case e := <-c.events.Chan():
   240  		t.Errorf("unexpected events comes: %v", e)
   241  	case <-timeout.C:
   242  		// success
   243  	}
   244  }
   245  
   246  func TestProcessBacklog(t *testing.T) {
   247  	v := &podc.View{
   248  		Round:    big.NewInt(0),
   249  		Sequence: big.NewInt(1),
   250  	}
   251  	preprepare := &podc.Preprepare{
   252  		View:     v,
   253  		Proposal: makeBlock(1),
   254  	}
   255  	prepreparePayload, _ := Encode(preprepare)
   256  
   257  	subject := &podc.Subject{
   258  		View:   v,
   259  		Digest: common.StringToHash("1234567890"),
   260  	}
   261  	subjectPayload, _ := Encode(subject)
   262  
   263  	msgs := []*message{
   264  		&message{
   265  			Code: msgPreprepare,
   266  			Msg:  prepreparePayload,
   267  		},
   268  		&message{
   269  			Code: msgDSelect,
   270  			Msg:  subjectPayload,
   271  		},
   272  		&message{
   273  			Code: msgDCommit,
   274  			Msg:  subjectPayload,
   275  		},
   276  	}
   277  	for i := 0; i < len(msgs); i++ {
   278  		testProcessBacklog(t, msgs[i])
   279  	}
   280  }
   281  
   282  func testProcessBacklog(t *testing.T, msg *message) {
   283  	vset := newTestValidatorSet(1)
   284  	backend := &testSystemBackend{
   285  		events: new(event.TypeMux),
   286  		peers:  vset,
   287  	}
   288  	c := &core{
   289  		logger:     log.New("backend", "test", "id", 0),
   290  		backlogs:   make(map[podc.Validator]*prque.Prque),
   291  		backlogsMu: new(sync.Mutex),
   292  		backend:    backend,
   293  		state:      State(msg.Code),
   294  		current: newRoundState(&podc.View{
   295  			Sequence: big.NewInt(1),
   296  			Round:    big.NewInt(0),
   297  		}, newTestValidatorSet(4)),
   298  	}
   299  	c.subscribeEvents()
   300  	defer c.unsubscribeEvents()
   301  
   302  	c.storeBacklog(msg, vset.GetByIndex(0))
   303  	c.processBacklog()
   304  
   305  	const timeoutDura = 2 * time.Second
   306  	timeout := time.NewTimer(timeoutDura)
   307  	select {
   308  	case ev := <-c.events.Chan():
   309  		e, ok := ev.Data.(backlogEvent)
   310  		if !ok {
   311  			t.Errorf("unexpected event comes: %v", reflect.TypeOf(ev.Data))
   312  		}
   313  		if e.msg.Code != msg.Code {
   314  			t.Errorf("message code mismatch: have %v, want %v", e.msg.Code, msg.Code)
   315  		}
   316  		// success
   317  	case <-timeout.C:
   318  		t.Error("unexpected timeout occurs")
   319  	}
   320  }