github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/network/simulation/events.go (about)

     1  // Copyright 2018 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 simulation
    18  
    19  import (
    20  	"context"
    21  	"sync"
    22  
    23  	"github.com/ethereum/go-ethereum/p2p/enode"
    24  	"github.com/ethereum/go-ethereum/p2p/simulations"
    25  )
    26  
    27  // PeerEvent is the type of the channel returned by Simulation.PeerEvents.
    28  type PeerEvent struct {
    29  	// NodeID is the ID of node that the event is caught on.
    30  	NodeID enode.ID
    31  	// PeerID is the ID of the peer node that the event is caught on.
    32  	PeerID enode.ID
    33  	// Event is the event that is caught.
    34  	Event *simulations.Event
    35  	// Error is the error that may have happened during event watching.
    36  	Error error
    37  }
    38  
    39  // PeerEventsFilter defines a filter on PeerEvents to exclude messages with
    40  // defined properties. Use PeerEventsFilter methods to set required options.
    41  type PeerEventsFilter struct {
    42  	eventType simulations.EventType
    43  
    44  	connUp *bool
    45  
    46  	msgReceive *bool
    47  	protocol   *string
    48  	msgCode    *uint64
    49  }
    50  
    51  // NewPeerEventsFilter returns a new PeerEventsFilter instance.
    52  func NewPeerEventsFilter() *PeerEventsFilter {
    53  	return &PeerEventsFilter{}
    54  }
    55  
    56  // Connect sets the filter to events when two nodes connect.
    57  func (f *PeerEventsFilter) Connect() *PeerEventsFilter {
    58  	f.eventType = simulations.EventTypeConn
    59  	b := true
    60  	f.connUp = &b
    61  	return f
    62  }
    63  
    64  // Drop sets the filter to events when two nodes disconnect.
    65  func (f *PeerEventsFilter) Drop() *PeerEventsFilter {
    66  	f.eventType = simulations.EventTypeConn
    67  	b := false
    68  	f.connUp = &b
    69  	return f
    70  }
    71  
    72  // ReceivedMessages sets the filter to only messages that are received.
    73  func (f *PeerEventsFilter) ReceivedMessages() *PeerEventsFilter {
    74  	f.eventType = simulations.EventTypeMsg
    75  	b := true
    76  	f.msgReceive = &b
    77  	return f
    78  }
    79  
    80  // SentMessages sets the filter to only messages that are sent.
    81  func (f *PeerEventsFilter) SentMessages() *PeerEventsFilter {
    82  	f.eventType = simulations.EventTypeMsg
    83  	b := false
    84  	f.msgReceive = &b
    85  	return f
    86  }
    87  
    88  // Protocol sets the filter to only one message protocol.
    89  func (f *PeerEventsFilter) Protocol(p string) *PeerEventsFilter {
    90  	f.eventType = simulations.EventTypeMsg
    91  	f.protocol = &p
    92  	return f
    93  }
    94  
    95  // MsgCode sets the filter to only one msg code.
    96  func (f *PeerEventsFilter) MsgCode(c uint64) *PeerEventsFilter {
    97  	f.eventType = simulations.EventTypeMsg
    98  	f.msgCode = &c
    99  	return f
   100  }
   101  
   102  // PeerEvents returns a channel of events that are captured by admin peerEvents
   103  // subscription nodes with provided NodeIDs. Additional filters can be set to ignore
   104  // events that are not relevant.
   105  func (s *Simulation) PeerEvents(ctx context.Context, ids []enode.ID, filters ...*PeerEventsFilter) <-chan PeerEvent {
   106  	eventC := make(chan PeerEvent)
   107  
   108  	// wait group to make sure all subscriptions to admin peerEvents are established
   109  	// before this function returns.
   110  	var subsWG sync.WaitGroup
   111  	for _, id := range ids {
   112  		s.shutdownWG.Add(1)
   113  		subsWG.Add(1)
   114  		go func(id enode.ID) {
   115  			defer s.shutdownWG.Done()
   116  
   117  			events := make(chan *simulations.Event)
   118  			sub := s.Net.Events().Subscribe(events)
   119  			defer sub.Unsubscribe()
   120  
   121  			subsWG.Done()
   122  
   123  			for {
   124  				select {
   125  				case <-ctx.Done():
   126  					if err := ctx.Err(); err != nil {
   127  						select {
   128  						case eventC <- PeerEvent{NodeID: id, Error: err}:
   129  						case <-s.Done():
   130  						}
   131  					}
   132  					return
   133  				case <-s.Done():
   134  					return
   135  				case e := <-events:
   136  					// ignore control events
   137  					if e.Control {
   138  						continue
   139  					}
   140  					match := len(filters) == 0 // if there are no filters match all events
   141  					for _, f := range filters {
   142  						if f.eventType == simulations.EventTypeConn && e.Conn != nil {
   143  							if *f.connUp != e.Conn.Up {
   144  								continue
   145  							}
   146  							// all connection filter parameters matched, break the loop
   147  							match = true
   148  							break
   149  						}
   150  						if f.eventType == simulations.EventTypeMsg && e.Msg != nil {
   151  							if f.msgReceive != nil && *f.msgReceive != e.Msg.Received {
   152  								continue
   153  							}
   154  							if f.protocol != nil && *f.protocol != e.Msg.Protocol {
   155  								continue
   156  							}
   157  							if f.msgCode != nil && *f.msgCode != e.Msg.Code {
   158  								continue
   159  							}
   160  							// all message filter parameters matched, break the loop
   161  							match = true
   162  							break
   163  						}
   164  					}
   165  					var peerID enode.ID
   166  					switch e.Type {
   167  					case simulations.EventTypeConn:
   168  						peerID = e.Conn.One
   169  						if peerID == id {
   170  							peerID = e.Conn.Other
   171  						}
   172  					case simulations.EventTypeMsg:
   173  						peerID = e.Msg.One
   174  						if peerID == id {
   175  							peerID = e.Msg.Other
   176  						}
   177  					}
   178  					if match {
   179  						select {
   180  						case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Event: e}:
   181  						case <-ctx.Done():
   182  							if err := ctx.Err(); err != nil {
   183  								select {
   184  								case eventC <- PeerEvent{NodeID: id, PeerID: peerID, Error: err}:
   185  								case <-s.Done():
   186  								}
   187  							}
   188  							return
   189  						case <-s.Done():
   190  							return
   191  						}
   192  					}
   193  				case err := <-sub.Err():
   194  					if err != nil {
   195  						select {
   196  						case eventC <- PeerEvent{NodeID: id, Error: err}:
   197  						case <-ctx.Done():
   198  							if err := ctx.Err(); err != nil {
   199  								select {
   200  								case eventC <- PeerEvent{NodeID: id, Error: err}:
   201  								case <-s.Done():
   202  								}
   203  							}
   204  							return
   205  						case <-s.Done():
   206  							return
   207  						}
   208  					}
   209  				}
   210  			}
   211  		}(id)
   212  	}
   213  
   214  	// wait all subscriptions
   215  	subsWG.Wait()
   216  	return eventC
   217  }