github.com/kisexp/xdchain@v0.0.0-20211206025815-490d6b732aa7/consensus/istanbul/ibft/core/backlog_test.go (about)

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