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