github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/p2p/simulations/simulation.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // Copyright 2019 The go-aigar Authors 3 // This file is part of the go-aigar library. 4 // 5 // The go-aigar library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-aigar library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-aigar library. If not, see <http://www.gnu.org/licenses/>. 17 18 package simulations 19 20 import ( 21 "context" 22 "time" 23 24 "github.com/AigarNetwork/aigar/p2p/enode" 25 ) 26 27 // Simulation provides a framework for running actions in a simulated network 28 // and then waiting for expectations to be met 29 type Simulation struct { 30 network *Network 31 } 32 33 // NewSimulation returns a new simulation which runs in the given network 34 func NewSimulation(network *Network) *Simulation { 35 return &Simulation{ 36 network: network, 37 } 38 } 39 40 // Run performs a step of the simulation by performing the step's action and 41 // then waiting for the step's expectation to be met 42 func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) { 43 result = newStepResult() 44 45 result.StartedAt = time.Now() 46 defer func() { result.FinishedAt = time.Now() }() 47 48 // watch network events for the duration of the step 49 stop := s.watchNetwork(result) 50 defer stop() 51 52 // perform the action 53 if err := step.Action(ctx); err != nil { 54 result.Error = err 55 return 56 } 57 58 // wait for all node expectations to either pass, error or timeout 59 nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes)) 60 for _, id := range step.Expect.Nodes { 61 nodes[id] = struct{}{} 62 } 63 for len(result.Passes) < len(nodes) { 64 select { 65 case id := <-step.Trigger: 66 // skip if we aren't checking the node 67 if _, ok := nodes[id]; !ok { 68 continue 69 } 70 71 // skip if the node has already passed 72 if _, ok := result.Passes[id]; ok { 73 continue 74 } 75 76 // run the node expectation check 77 pass, err := step.Expect.Check(ctx, id) 78 if err != nil { 79 result.Error = err 80 return 81 } 82 if pass { 83 result.Passes[id] = time.Now() 84 } 85 case <-ctx.Done(): 86 result.Error = ctx.Err() 87 return 88 } 89 } 90 91 return 92 } 93 94 func (s *Simulation) watchNetwork(result *StepResult) func() { 95 stop := make(chan struct{}) 96 done := make(chan struct{}) 97 events := make(chan *Event) 98 sub := s.network.Events().Subscribe(events) 99 go func() { 100 defer close(done) 101 defer sub.Unsubscribe() 102 for { 103 select { 104 case event := <-events: 105 result.NetworkEvents = append(result.NetworkEvents, event) 106 case <-stop: 107 return 108 } 109 } 110 }() 111 return func() { 112 close(stop) 113 <-done 114 } 115 } 116 117 type Step struct { 118 // Action is the action to perform for this step 119 Action func(context.Context) error 120 121 // Trigger is a channel which receives node ids and triggers an 122 // expectation check for that node 123 Trigger chan enode.ID 124 125 // Expect is the expectation to wait for when performing this step 126 Expect *Expectation 127 } 128 129 type Expectation struct { 130 // Nodes is a list of nodes to check 131 Nodes []enode.ID 132 133 // Check checks whether a given node meets the expectation 134 Check func(context.Context, enode.ID) (bool, error) 135 } 136 137 func newStepResult() *StepResult { 138 return &StepResult{ 139 Passes: make(map[enode.ID]time.Time), 140 } 141 } 142 143 type StepResult struct { 144 // Error is the error encountered whilst running the step 145 Error error 146 147 // StartedAt is the time the step started 148 StartedAt time.Time 149 150 // FinishedAt is the time the step finished 151 FinishedAt time.Time 152 153 // Passes are the timestamps of the successful node expectations 154 Passes map[enode.ID]time.Time 155 156 // NetworkEvents are the network events which occurred during the step 157 NetworkEvents []*Event 158 }