github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/consensus/dbft/core/backlog_test.go (about)

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