simulation.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2017 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. package simulations
  17. import (
  18. "context"
  19. "time"
  20. "github.com/ethereum/go-ethereum/p2p/enode"
  21. )
  22. // Simulation provides a framework for running actions in a simulated network
  23. // and then waiting for expectations to be met
  24. type Simulation struct {
  25. network *Network
  26. }
  27. // NewSimulation returns a new simulation which runs in the given network
  28. func NewSimulation(network *Network) *Simulation {
  29. return &Simulation{
  30. network: network,
  31. }
  32. }
  33. // Run performs a step of the simulation by performing the step's action and
  34. // then waiting for the step's expectation to be met
  35. func (s *Simulation) Run(ctx context.Context, step *Step) (result *StepResult) {
  36. result = newStepResult()
  37. result.StartedAt = time.Now()
  38. defer func() { result.FinishedAt = time.Now() }()
  39. // watch network events for the duration of the step
  40. stop := s.watchNetwork(result)
  41. defer stop()
  42. // perform the action
  43. if err := step.Action(ctx); err != nil {
  44. result.Error = err
  45. return
  46. }
  47. // wait for all node expectations to either pass, error or timeout
  48. nodes := make(map[enode.ID]struct{}, len(step.Expect.Nodes))
  49. for _, id := range step.Expect.Nodes {
  50. nodes[id] = struct{}{}
  51. }
  52. for len(result.Passes) < len(nodes) {
  53. select {
  54. case id := <-step.Trigger:
  55. // skip if we aren't checking the node
  56. if _, ok := nodes[id]; !ok {
  57. continue
  58. }
  59. // skip if the node has already passed
  60. if _, ok := result.Passes[id]; ok {
  61. continue
  62. }
  63. // run the node expectation check
  64. pass, err := step.Expect.Check(ctx, id)
  65. if err != nil {
  66. result.Error = err
  67. return
  68. }
  69. if pass {
  70. result.Passes[id] = time.Now()
  71. }
  72. case <-ctx.Done():
  73. result.Error = ctx.Err()
  74. return
  75. }
  76. }
  77. return
  78. }
  79. func (s *Simulation) watchNetwork(result *StepResult) func() {
  80. stop := make(chan struct{})
  81. done := make(chan struct{})
  82. events := make(chan *Event)
  83. sub := s.network.Events().Subscribe(events)
  84. go func() {
  85. defer close(done)
  86. defer sub.Unsubscribe()
  87. for {
  88. select {
  89. case event := <-events:
  90. result.NetworkEvents = append(result.NetworkEvents, event)
  91. case <-stop:
  92. return
  93. }
  94. }
  95. }()
  96. return func() {
  97. close(stop)
  98. <-done
  99. }
  100. }
  101. type Step struct {
  102. // Action is the action to perform for this step
  103. Action func(context.Context) error
  104. // Trigger is a channel which receives node ids and triggers an
  105. // expectation check for that node
  106. Trigger chan enode.ID
  107. // Expect is the expectation to wait for when performing this step
  108. Expect *Expectation
  109. }
  110. type Expectation struct {
  111. // Nodes is a list of nodes to check
  112. Nodes []enode.ID
  113. // Check checks whether a given node meets the expectation
  114. Check func(context.Context, enode.ID) (bool, error)
  115. }
  116. func newStepResult() *StepResult {
  117. return &StepResult{
  118. Passes: make(map[enode.ID]time.Time),
  119. }
  120. }
  121. type StepResult struct {
  122. // Error is the error encountered whilst running the step
  123. Error error
  124. // StartedAt is the time the step started
  125. StartedAt time.Time
  126. // FinishedAt is the time the step finished
  127. FinishedAt time.Time
  128. // Passes are the timestamps of the successful node expectations
  129. Passes map[enode.ID]time.Time
  130. // NetworkEvents are the network events which occurred during the step
  131. NetworkEvents []*Event
  132. }