github.com/ConsenSys/Quorum@v20.10.0+incompatible/consensus/istanbul/backend/handler_test.go (about)

     1  // Copyright 2015 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 backend
    18  
    19  import (
    20  	"bytes"
    21  	"io/ioutil"
    22  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/consensus/istanbul"
    27  	"github.com/ethereum/go-ethereum/core/types"
    28  	"github.com/ethereum/go-ethereum/p2p"
    29  	"github.com/ethereum/go-ethereum/rlp"
    30  	lru "github.com/hashicorp/golang-lru"
    31  )
    32  
    33  func TestIstanbulMessage(t *testing.T) {
    34  	_, backend := newBlockChain(1)
    35  
    36  	// generate one msg
    37  	data := []byte("data1")
    38  	hash := istanbul.RLPHash(data)
    39  	msg := makeMsg(istanbulMsg, data)
    40  	addr := common.StringToAddress("address")
    41  
    42  	// 1. this message should not be in cache
    43  	// for peers
    44  	if _, ok := backend.recentMessages.Get(addr); ok {
    45  		t.Fatalf("the cache of messages for this peer should be nil")
    46  	}
    47  
    48  	// for self
    49  	if _, ok := backend.knownMessages.Get(hash); ok {
    50  		t.Fatalf("the cache of messages should be nil")
    51  	}
    52  
    53  	// 2. this message should be in cache after we handle it
    54  	_, err := backend.HandleMsg(addr, msg)
    55  	if err != nil {
    56  		t.Fatalf("handle message failed: %v", err)
    57  	}
    58  	// for peers
    59  	if ms, ok := backend.recentMessages.Get(addr); ms == nil || !ok {
    60  		t.Fatalf("the cache of messages for this peer cannot be nil")
    61  	} else if m, ok := ms.(*lru.ARCCache); !ok {
    62  		t.Fatalf("the cache of messages for this peer cannot be casted")
    63  	} else if _, ok := m.Get(hash); !ok {
    64  		t.Fatalf("the cache of messages for this peer cannot be found")
    65  	}
    66  
    67  	// for self
    68  	if _, ok := backend.knownMessages.Get(hash); !ok {
    69  		t.Fatalf("the cache of messages cannot be found")
    70  	}
    71  }
    72  
    73  func makeMsg(msgcode uint64, data interface{}) p2p.Msg {
    74  	size, r, _ := rlp.EncodeToReader(data)
    75  	return p2p.Msg{Code: msgcode, Size: uint32(size), Payload: r}
    76  }
    77  
    78  func TestHandleNewBlockMessage_whenTypical(t *testing.T) {
    79  	_, backend := newBlockChain(1)
    80  	arbitraryAddress := common.StringToAddress("arbitrary")
    81  	arbitraryBlock, arbitraryP2PMessage := buildArbitraryP2PNewBlockMessage(t, false)
    82  	postAndWait(backend, arbitraryBlock, t)
    83  
    84  	handled, err := backend.HandleMsg(arbitraryAddress, arbitraryP2PMessage)
    85  
    86  	if err != nil {
    87  		t.Errorf("expected message being handled successfully but got %s", err)
    88  	}
    89  	if !handled {
    90  		t.Errorf("expected message being handled but not")
    91  	}
    92  	if _, err := ioutil.ReadAll(arbitraryP2PMessage.Payload); err != nil {
    93  		t.Errorf("expected p2p message payload is restored")
    94  	}
    95  }
    96  
    97  func TestHandleNewBlockMessage_whenNotAProposedBlock(t *testing.T) {
    98  	_, backend := newBlockChain(1)
    99  	arbitraryAddress := common.StringToAddress("arbitrary")
   100  	_, arbitraryP2PMessage := buildArbitraryP2PNewBlockMessage(t, false)
   101  	postAndWait(backend, types.NewBlock(&types.Header{
   102  		Number:    big.NewInt(1),
   103  		Root:      common.StringToHash("someroot"),
   104  		GasLimit:  1,
   105  		MixDigest: types.IstanbulDigest,
   106  	}, nil, nil, nil), t)
   107  
   108  	handled, err := backend.HandleMsg(arbitraryAddress, arbitraryP2PMessage)
   109  
   110  	if err != nil {
   111  		t.Errorf("expected message being handled successfully but got %s", err)
   112  	}
   113  	if handled {
   114  		t.Errorf("expected message not being handled")
   115  	}
   116  	if _, err := ioutil.ReadAll(arbitraryP2PMessage.Payload); err != nil {
   117  		t.Errorf("expected p2p message payload is restored")
   118  	}
   119  }
   120  
   121  func TestHandleNewBlockMessage_whenFailToDecode(t *testing.T) {
   122  	_, backend := newBlockChain(1)
   123  	arbitraryAddress := common.StringToAddress("arbitrary")
   124  	_, arbitraryP2PMessage := buildArbitraryP2PNewBlockMessage(t, true)
   125  	postAndWait(backend, types.NewBlock(&types.Header{
   126  		Number:    big.NewInt(1),
   127  		GasLimit:  1,
   128  		MixDigest: types.IstanbulDigest,
   129  	}, nil, nil, nil), t)
   130  
   131  	handled, err := backend.HandleMsg(arbitraryAddress, arbitraryP2PMessage)
   132  
   133  	if err != nil {
   134  		t.Errorf("expected message being handled successfully but got %s", err)
   135  	}
   136  	if handled {
   137  		t.Errorf("expected message not being handled")
   138  	}
   139  	if _, err := ioutil.ReadAll(arbitraryP2PMessage.Payload); err != nil {
   140  		t.Errorf("expected p2p message payload is restored")
   141  	}
   142  }
   143  
   144  func postAndWait(backend *backend, block *types.Block, t *testing.T) {
   145  	eventSub := backend.EventMux().Subscribe(istanbul.RequestEvent{})
   146  	defer eventSub.Unsubscribe()
   147  	stop := make(chan struct{}, 1)
   148  	eventLoop := func() {
   149  		<-eventSub.Chan()
   150  		stop <- struct{}{}
   151  	}
   152  	go eventLoop()
   153  	if err := backend.EventMux().Post(istanbul.RequestEvent{
   154  		Proposal: block,
   155  	}); err != nil {
   156  		t.Fatalf("%s", err)
   157  	}
   158  	<-stop
   159  }
   160  
   161  func buildArbitraryP2PNewBlockMessage(t *testing.T, invalidMsg bool) (*types.Block, p2p.Msg) {
   162  	arbitraryBlock := types.NewBlock(&types.Header{
   163  		Number:    big.NewInt(1),
   164  		GasLimit:  0,
   165  		MixDigest: types.IstanbulDigest,
   166  	}, nil, nil, nil)
   167  	request := []interface{}{&arbitraryBlock, big.NewInt(1)}
   168  	if invalidMsg {
   169  		request = []interface{}{"invalid msg"}
   170  	}
   171  	size, r, err := rlp.EncodeToReader(request)
   172  	if err != nil {
   173  		t.Fatalf("can't encode due to %s", err)
   174  	}
   175  	payload, err := ioutil.ReadAll(r)
   176  	if err != nil {
   177  		t.Fatalf("can't read payload due to %s", err)
   178  	}
   179  	arbitraryP2PMessage := p2p.Msg{Code: 0x07, Size: uint32(size), Payload: bytes.NewReader(payload)}
   180  	return arbitraryBlock, arbitraryP2PMessage
   181  }