github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/consensus/istanbul/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  	"fmt"
    21  	blscrypto "github.com/ethereum/go-ethereum/crypto/bls"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/consensus/istanbul"
    29  	"github.com/ethereum/go-ethereum/consensus/istanbul/validator"
    30  	"github.com/ethereum/go-ethereum/event"
    31  	elog "github.com/ethereum/go-ethereum/log"
    32  )
    33  
    34  func TestCheckMessage(t *testing.T) {
    35  	testLogger.SetHandler(elog.StdoutHandler)
    36  	backend := &testSystemBackend{
    37  		events: new(event.TypeMux),
    38  	}
    39  	valSet := newTestValidatorSet(4)
    40  	c := &core{
    41  		logger:  testLogger,
    42  		backend: backend,
    43  		current: newRoundState(&istanbul.View{
    44  			Sequence: big.NewInt(2),
    45  			Round:    big.NewInt(2),
    46  		}, valSet, valSet.GetByIndex(0)),
    47  	}
    48  
    49  	t.Run("invalid view format", func(t *testing.T) {
    50  		err := c.checkMessage(istanbul.MsgPreprepare, nil)
    51  		if err != errInvalidMessage {
    52  			t.Errorf("error mismatch: have %v, want %v", err, errInvalidMessage)
    53  		}
    54  	})
    55  
    56  	testStates := []State{StateAcceptRequest, StatePreprepared, StatePrepared, StateCommitted, StateWaitingForNewRound}
    57  	testCodes := []uint64{istanbul.MsgPreprepare, istanbul.MsgPrepare, istanbul.MsgCommit, istanbul.MsgRoundChange}
    58  
    59  	// accept Commits from sequence, round matching LastSubject
    60  	t.Run("Rejects all other older rounds", func(t *testing.T) {
    61  		v := &istanbul.View{
    62  			Sequence: big.NewInt(2),
    63  			Round:    big.NewInt(1),
    64  		}
    65  		for _, testState := range testStates {
    66  			for _, testCode := range testCodes {
    67  				c.current.(*roundStateImpl).state = testState
    68  				err := c.checkMessage(testCode, v)
    69  
    70  				if err != errOldMessage {
    71  					t.Errorf("error mismatch: have %v, want %v", err, errOldMessage)
    72  				}
    73  
    74  			}
    75  		}
    76  	})
    77  
    78  	t.Run("Rejects all other older sequences", func(t *testing.T) {
    79  		v := &istanbul.View{
    80  			Sequence: big.NewInt(0),
    81  			Round:    big.NewInt(0),
    82  		}
    83  		for _, testState := range testStates {
    84  			for _, testCode := range testCodes {
    85  				c.current.(*roundStateImpl).state = testState
    86  				err := c.checkMessage(testCode, v)
    87  				if err != errOldMessage {
    88  					t.Errorf("error mismatch: have %v, want %v", err, errOldMessage)
    89  				}
    90  			}
    91  		}
    92  	})
    93  
    94  	t.Run("Future sequence", func(t *testing.T) {
    95  		v := &istanbul.View{
    96  			Sequence: big.NewInt(3),
    97  			Round:    big.NewInt(0),
    98  		}
    99  		for _, testState := range testStates {
   100  			for _, testCode := range testCodes {
   101  				c.current.(*roundStateImpl).state = testState
   102  				err := c.checkMessage(testCode, v)
   103  				if err != errFutureMessage {
   104  					t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
   105  				}
   106  			}
   107  		}
   108  	})
   109  
   110  	t.Run("future round", func(t *testing.T) {
   111  		v := &istanbul.View{
   112  			Sequence: big.NewInt(2),
   113  			Round:    big.NewInt(3),
   114  		}
   115  		for _, testState := range testStates {
   116  			for _, testCode := range testCodes {
   117  				c.current.(*roundStateImpl).state = testState
   118  				err := c.checkMessage(testCode, v)
   119  				if testCode == istanbul.MsgRoundChange {
   120  					if err != nil {
   121  						t.Errorf("error mismatch: have %v, want nil", err)
   122  					}
   123  				} else if err != errFutureMessage {
   124  					t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
   125  				}
   126  			}
   127  		}
   128  	})
   129  
   130  	t.Run("current view, state = StateAcceptRequest", func(t *testing.T) {
   131  		v := c.current.View()
   132  		c.current.(*roundStateImpl).state = StateAcceptRequest
   133  
   134  		for _, testCode := range testCodes {
   135  			err := c.checkMessage(testCode, v)
   136  			if testCode == istanbul.MsgRoundChange {
   137  				if err != nil {
   138  					t.Errorf("error mismatch: have %v, want nil", err)
   139  				}
   140  			} else if testCode == istanbul.MsgPreprepare {
   141  				if err != nil {
   142  					t.Errorf("error mismatch: have %v, want nil", err)
   143  				}
   144  			} else {
   145  				if err != errFutureMessage {
   146  					t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
   147  				}
   148  			}
   149  		}
   150  	})
   151  
   152  	t.Run("current view, state = StatePreprepared", func(t *testing.T) {
   153  		v := c.current.View()
   154  		c.current.(*roundStateImpl).state = StatePreprepared
   155  		for _, testCode := range testCodes {
   156  			err := c.checkMessage(testCode, v)
   157  			if testCode == istanbul.MsgRoundChange {
   158  				if err != nil {
   159  					t.Errorf("error mismatch: have %v, want nil", err)
   160  				}
   161  			} else if err != nil {
   162  				t.Errorf("error mismatch: have %v, want nil", err)
   163  			}
   164  		}
   165  	})
   166  
   167  	t.Run("current view, state = StatePrepared", func(t *testing.T) {
   168  		v := c.current.View()
   169  		c.current.(*roundStateImpl).state = StatePrepared
   170  		for _, testCode := range testCodes {
   171  			err := c.checkMessage(testCode, v)
   172  			if testCode == istanbul.MsgRoundChange {
   173  				if err != nil {
   174  					t.Errorf("error mismatch: have %v, want nil", err)
   175  				}
   176  			} else if err != nil {
   177  				t.Errorf("error mismatch: have %v, want nil", err)
   178  			}
   179  		}
   180  	})
   181  
   182  	t.Run("current view, state = StateCommited", func(t *testing.T) {
   183  		v := c.current.View()
   184  		c.current.(*roundStateImpl).state = StateCommitted
   185  		for _, testCode := range testCodes {
   186  			err := c.checkMessage(testCode, v)
   187  			if testCode == istanbul.MsgRoundChange {
   188  				if err != nil {
   189  					t.Errorf("error mismatch: have %v, want nil", err)
   190  				}
   191  			} else if err != nil {
   192  				t.Errorf("error mismatch: have %v, want nil", err)
   193  			}
   194  		}
   195  	})
   196  
   197  	t.Run("current view, state = StateWaitingForNewRound", func(t *testing.T) {
   198  		v := c.current.View()
   199  		c.current.(*roundStateImpl).state = StateWaitingForNewRound
   200  		for _, testCode := range testCodes {
   201  			err := c.checkMessage(testCode, v)
   202  			if testCode == istanbul.MsgRoundChange {
   203  				if err != nil {
   204  					t.Errorf("error mismatch: have %v, want nil", err)
   205  				}
   206  			} else if err != errFutureMessage {
   207  				t.Errorf("error mismatch: have %v, want %v", err, errFutureMessage)
   208  			}
   209  		}
   210  	})
   211  
   212  }
   213  
   214  func TestStoreBacklog(t *testing.T) {
   215  	testLogger.SetHandler(elog.StdoutHandler)
   216  	backlog := newMsgBacklog(
   217  		func(msg *istanbul.Message) {},
   218  		func(msgCode uint64, msgView *istanbul.View) error { return nil },
   219  	).(*msgBacklogImpl)
   220  
   221  	v10 := &istanbul.View{
   222  		Round:    big.NewInt(10),
   223  		Sequence: big.NewInt(10),
   224  	}
   225  
   226  	v11 := &istanbul.View{
   227  		Round:    big.NewInt(12),
   228  		Sequence: big.NewInt(11),
   229  	}
   230  	p1 := validator.New(common.BytesToAddress([]byte("12345667890")), blscrypto.SerializedPublicKey{})
   231  	p2 := validator.New(common.BytesToAddress([]byte("47324349949")), blscrypto.SerializedPublicKey{})
   232  
   233  	// push messages
   234  	preprepare := &istanbul.Preprepare{
   235  		View:     v10,
   236  		Proposal: makeBlock(10),
   237  	}
   238  
   239  	prepreparePayload, _ := Encode(preprepare)
   240  	mPreprepare := &istanbul.Message{
   241  		Code:    istanbul.MsgPreprepare,
   242  		Msg:     prepreparePayload,
   243  		Address: p1.Address(),
   244  	}
   245  
   246  	backlog.store(mPreprepare)
   247  
   248  	msg := backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem()
   249  	if !reflect.DeepEqual(msg, mPreprepare) {
   250  		t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare)
   251  	}
   252  
   253  	subject := &istanbul.Subject{
   254  		View:   v10,
   255  		Digest: common.BytesToHash([]byte("1234567890")),
   256  	}
   257  	subjectPayload, _ := Encode(subject)
   258  	mPrepare := &istanbul.Message{
   259  		Code:    istanbul.MsgPrepare,
   260  		Msg:     subjectPayload,
   261  		Address: p1.Address(),
   262  	}
   263  
   264  	preprepare2 := &istanbul.Preprepare{
   265  		View:     v11,
   266  		Proposal: makeBlock(11),
   267  	}
   268  	preprepare2Payload, _ := Encode(preprepare2)
   269  	mPreprepare2 := &istanbul.Message{
   270  		Code:    istanbul.MsgPreprepare,
   271  		Msg:     preprepare2Payload,
   272  		Address: p2.Address(),
   273  	}
   274  
   275  	backlog.store(mPreprepare)
   276  	backlog.store(mPrepare)
   277  	backlog.store(mPreprepare2)
   278  
   279  	if backlog.msgCountBySrc[p1.Address()] != 3 {
   280  		t.Errorf("msgCountBySrc mismatch: have %v, want 3", backlog.msgCountBySrc[p1.Address()])
   281  	}
   282  	// push commit msg
   283  	committedSubject := &istanbul.CommittedSubject{
   284  		Subject:       subject,
   285  		CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F}, // celo in hex!
   286  	}
   287  
   288  	committedSubjectPayload, _ := Encode(committedSubject)
   289  
   290  	mCommit := &istanbul.Message{
   291  		Code:    istanbul.MsgCommit,
   292  		Msg:     committedSubjectPayload,
   293  		Address: p1.Address(),
   294  	}
   295  
   296  	backlog.store(mCommit)
   297  	if backlog.msgCountBySrc[p2.Address()] != 1 {
   298  		t.Errorf("msgCountBySrc mismatch: have %v, want 1", backlog.msgCountBySrc[p2.Address()])
   299  	}
   300  	if backlog.msgCount != 5 {
   301  		t.Errorf("msgCount mismatch: have %v, want 5", backlog.msgCount)
   302  	}
   303  
   304  	// Should get back v10 preprepare then commit
   305  	msg = backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem()
   306  	if !reflect.DeepEqual(msg, mPreprepare) {
   307  		t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare2)
   308  	}
   309  	msg = backlog.backlogBySeq[v10.Sequence.Uint64()].PopItem()
   310  	if !reflect.DeepEqual(msg, mCommit) {
   311  		t.Errorf("message mismatch: have %v, want %v", msg, mCommit)
   312  
   313  	}
   314  	msg = backlog.backlogBySeq[v11.Sequence.Uint64()].PopItem()
   315  	if !reflect.DeepEqual(msg, mPreprepare2) {
   316  		t.Errorf("message mismatch: have %v, want %v", msg, mPreprepare2)
   317  	}
   318  
   319  	backlog.msgCount = 0
   320  	delete(backlog.msgCountBySrc, p1.Address())
   321  	delete(backlog.msgCountBySrc, p2.Address())
   322  }
   323  
   324  func TestProcessFutureBacklog(t *testing.T) {
   325  	testLogger.SetHandler(elog.StdoutHandler)
   326  
   327  	backlog := newMsgBacklog(
   328  		func(msg *istanbul.Message) {},
   329  		func(msgCode uint64, msgView *istanbul.View) error { return nil },
   330  	).(*msgBacklogImpl)
   331  
   332  	// push a future msg
   333  	v := &istanbul.View{
   334  		Round:    big.NewInt(10),
   335  		Sequence: big.NewInt(10),
   336  	}
   337  
   338  	committedSubject := &istanbul.CommittedSubject{
   339  		Subject: &istanbul.Subject{
   340  			View:   v,
   341  			Digest: common.BytesToHash([]byte("1234567890")),
   342  		},
   343  		CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F},
   344  	}
   345  
   346  	committedSubjectPayload, _ := Encode(committedSubject)
   347  	// push a future msg
   348  	valSet := newTestValidatorSet(4)
   349  	mFuture := &istanbul.Message{
   350  		Code:    istanbul.MsgCommit,
   351  		Msg:     committedSubjectPayload,
   352  		Address: valSet.GetByIndex(0).Address(),
   353  	}
   354  	backlog.store(mFuture)
   355  
   356  	// push a message from the past and check we expire it
   357  	v0 := &istanbul.View{
   358  		Round:    big.NewInt(0),
   359  		Sequence: big.NewInt(0),
   360  	}
   361  	subject0 := &istanbul.Subject{
   362  		View:   v0,
   363  		Digest: common.BytesToHash([]byte("1234567890")),
   364  	}
   365  	subjectPayload0, _ := Encode(subject0)
   366  	mPast := &istanbul.Message{
   367  		Code:    istanbul.MsgRoundChange,
   368  		Msg:     subjectPayload0,
   369  		Address: valSet.GetByIndex(1).Address(),
   370  	}
   371  	backlog.store(mPast)
   372  
   373  	backlogSeqs := backlog.getSortedBacklogSeqs()
   374  	if len(backlogSeqs) != 1 || backlogSeqs[0] != v.Sequence.Uint64() {
   375  		t.Errorf("getSortedBacklogSeqs mismatch: have %v", backlogSeqs)
   376  	}
   377  
   378  	backlog.updateState(&istanbul.View{
   379  		Sequence: big.NewInt(1),
   380  		Round:    big.NewInt(0),
   381  	}, StateAcceptRequest)
   382  
   383  	// Check message from future remains, past expired
   384  	if backlog.msgCount != 1 || backlog.msgCountBySrc[valSet.GetByIndex(1).Address()] > 0 {
   385  		t.Errorf("backlog mismatch: %v", backlog.msgCountBySrc)
   386  	}
   387  }
   388  
   389  func TestProcessBacklog(t *testing.T) {
   390  	v := &istanbul.View{
   391  		Round:    big.NewInt(0),
   392  		Sequence: big.NewInt(1),
   393  	}
   394  	preprepare := &istanbul.Preprepare{
   395  		View:     v,
   396  		Proposal: makeBlock(1),
   397  	}
   398  	prepreparePayload, _ := Encode(preprepare)
   399  
   400  	subject := &istanbul.Subject{
   401  		View:   v,
   402  		Digest: common.BytesToHash([]byte("1234567890")),
   403  	}
   404  	subjectPayload, _ := Encode(subject)
   405  
   406  	committedSubject := &istanbul.CommittedSubject{
   407  		Subject:       subject,
   408  		CommittedSeal: []byte{0x63, 0x65, 0x6C, 0x6F},
   409  	}
   410  	committedSubjectPayload, _ := Encode(committedSubject)
   411  
   412  	rc := &istanbul.RoundChange{
   413  		View:                v,
   414  		PreparedCertificate: istanbul.EmptyPreparedCertificate(),
   415  	}
   416  	rcPayload, _ := Encode(rc)
   417  
   418  	address := common.BytesToAddress([]byte("0xce10ce10"))
   419  
   420  	msgs := []*istanbul.Message{
   421  		{
   422  			Code:    istanbul.MsgPreprepare,
   423  			Msg:     prepreparePayload,
   424  			Address: address,
   425  		},
   426  		{
   427  			Code:    istanbul.MsgPrepare,
   428  			Msg:     subjectPayload,
   429  			Address: address,
   430  		},
   431  		{
   432  			Code:    istanbul.MsgCommit,
   433  			Msg:     committedSubjectPayload,
   434  			Address: address,
   435  		},
   436  		{
   437  			Code:    istanbul.MsgRoundChange,
   438  			Msg:     rcPayload,
   439  			Address: address,
   440  		},
   441  	}
   442  	for i := 0; i < len(msgs); i++ {
   443  		t.Run(fmt.Sprintf("Msg with code %d", msgs[i].Code), func(t *testing.T) {
   444  			testProcessBacklog(t, msgs[i])
   445  		})
   446  	}
   447  }
   448  
   449  func testProcessBacklog(t *testing.T, msg *istanbul.Message) {
   450  
   451  	testLogger.SetHandler(elog.StdoutHandler)
   452  
   453  	processedMsgs := make(chan uint64, 100)
   454  	registerCall := func(msg *istanbul.Message) {
   455  		processedMsgs <- msg.Code
   456  		// we expect only one msg
   457  		close(processedMsgs)
   458  	}
   459  
   460  	backlog := newMsgBacklog(
   461  		registerCall,
   462  		func(msgCode uint64, msgView *istanbul.View) error { return nil },
   463  	).(*msgBacklogImpl)
   464  
   465  	v := &istanbul.View{
   466  		Round:    big.NewInt(0),
   467  		Sequence: big.NewInt(1),
   468  	}
   469  
   470  	msg.Address = common.Address{50}
   471  	backlog.store(msg)
   472  
   473  	backlog.updateState(v, State(msg.Code))
   474  
   475  	timeout := time.NewTimer(1 * time.Second)
   476  
   477  	select {
   478  	case got := <-processedMsgs:
   479  		if got != msg.Code {
   480  			t.Errorf("Expected different msg: have: %v, want: %v", got, msg.Code)
   481  		}
   482  	case <-timeout.C:
   483  		t.Errorf("No Message was processed")
   484  	}
   485  
   486  }