github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/simulations/simulation.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:42</date>
    10  //</624450107256868865>
    11  
    12  
    13  package simulations
    14  
    15  import (
    16  	"context"
    17  	"time"
    18  
    19  	"github.com/ethereum/go-ethereum/p2p/enode"
    20  )
    21  
    22  //模拟为在模拟网络中运行操作提供了一个框架
    23  //然后等待期望得到满足
    24  type Simulation struct {
    25  	network *Network
    26  }
    27  
    28  //新模拟返回在给定网络中运行的新模拟
    29  func NewSimulation(network *Network) *Simulation {
    30  	return &Simulation{
    31  		network: network,
    32  	}
    33  }
    34  
    35  //运行通过执行步骤的操作执行模拟步骤,并
    36  //然后等待步骤的期望得到满足
    37  func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) {
    38  	result = newStepResult()
    39  
    40  	result.StartedAt = time.Now()
    41  	defer func() { result.FinishedAt = time.Now() }()
    42  
    43  //在步骤期间监视网络事件
    44  	stop := s.watchNetwork(result)
    45  	defer stop()
    46  
    47  //执行操作
    48  	if err := step.Action(ctx); err != nil {
    49  		result.Error = err
    50  		return
    51  	}
    52  
    53  //等待所有节点期望通过、错误或超时
    54  	nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes))
    55  	for _, id := range step.Expect.Nodes {
    56  		nodes[id] = struct{}{}
    57  	}
    58  	for len(result.Passes) < len(nodes) {
    59  		select {
    60  		case id := <-step.Trigger:
    61  //如果不检查节点,则跳过
    62  			if _, ok := nodes[id]; !ok {
    63  				continue
    64  			}
    65  
    66  //如果节点已通过,则跳过
    67  			if _, ok := result.Passes[id]; ok {
    68  				continue
    69  			}
    70  
    71  //运行节点期望检查
    72  			pass, err := step.Expect.Check(ctx, id)
    73  			if err != nil {
    74  				result.Error = err
    75  				return
    76  			}
    77  			if pass {
    78  				result.Passes[id] = time.Now()
    79  			}
    80  		case <-ctx.Done():
    81  			result.Error = ctx.Err()
    82  			return
    83  		}
    84  	}
    85  
    86  	return
    87  }
    88  
    89  func (s *Simulation) watchNetwork(result *StepResult) func() {
    90  	stop := make(chan struct{})
    91  	done := make(chan struct{})
    92  	events := make(chan *Event)
    93  	sub := s.network.Events().Subscribe(events)
    94  	go func() {
    95  		defer close(done)
    96  		defer sub.Unsubscribe()
    97  		for {
    98  			select {
    99  			case event := <-events:
   100  				result.NetworkEvents = append(result.NetworkEvents, event)
   101  			case <-stop:
   102  				return
   103  			}
   104  		}
   105  	}()
   106  	return func() {
   107  		close(stop)
   108  		<-done
   109  	}
   110  }
   111  
   112  type Step struct {
   113  //操作是为此步骤执行的操作
   114  	Action func(context.Context) error
   115  
   116  //触发器是一个接收节点ID并触发
   117  //该节点的预期检查
   118  	Trigger chan enode.ID
   119  
   120  //Expect是执行此步骤时等待的期望
   121  	Expect *Expectation
   122  }
   123  
   124  type Expectation struct {
   125  //节点是要检查的节点列表
   126  	Nodes []enode.ID
   127  
   128  //检查给定节点是否满足预期
   129  	Check func(context.Context, enode.ID) (bool, error)
   130  }
   131  
   132  func newStepResult() *StepResult {
   133  	return &StepResult{
   134  		Passes: make(map[enode.ID]time.Time),
   135  	}
   136  }
   137  
   138  type StepResult struct {
   139  //错误是运行步骤时遇到的错误
   140  	Error error
   141  
   142  //Startedat是步骤开始的时间
   143  	StartedAt time.Time
   144  
   145  //FinishedAt是步骤完成的时间。
   146  	FinishedAt time.Time
   147  
   148  //传递是成功节点期望的时间戳
   149  	Passes map[enode.ID]time.Time
   150  
   151  //NetworkEvents是在步骤中发生的网络事件。
   152  	NetworkEvents []*Event
   153  }
   154