mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
p2p/simulations: validate all connections on loading a snapshot
This commit is contained in:
parent
6fbdcb27f0
commit
49ca919900
1 changed files with 84 additions and 1 deletions
|
|
@ -20,7 +20,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -707,6 +709,7 @@ func (net *Network) snapshot(addServices []string, removeServices []string) (*Sn
|
||||||
|
|
||||||
// Load loads a network snapshot
|
// Load loads a network snapshot
|
||||||
func (net *Network) Load(snap *Snapshot) error {
|
func (net *Network) Load(snap *Snapshot) error {
|
||||||
|
// Start nodes.
|
||||||
for _, n := range snap.Nodes {
|
for _, n := range snap.Nodes {
|
||||||
if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil {
|
if _, err := net.NewNodeWithConfig(n.Node.Config); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -718,6 +721,78 @@ func (net *Network) Load(snap *Snapshot) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare connection events counter.
|
||||||
|
allConnected := make(chan struct{}) // closed when all connections are established
|
||||||
|
eventLoopStarted := make(chan struct{}) // ensures that event loop is started before it is closed
|
||||||
|
done := make(chan struct{}) // ensures that the event loop goroutine is terminated
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// Subscribe to event channel.
|
||||||
|
events := make(chan *Event)
|
||||||
|
sub := net.Events().Subscribe(events)
|
||||||
|
defer sub.Unsubscribe()
|
||||||
|
|
||||||
|
// Expected number of connections.
|
||||||
|
total := len(snap.Conns)
|
||||||
|
// counter tracks the current number of connections.
|
||||||
|
var counter int
|
||||||
|
|
||||||
|
// once is a closed channel that is read in the event loop below
|
||||||
|
// only once.
|
||||||
|
// It ensures that eventLoopStarted is closed which signals that
|
||||||
|
// it is safe to call connect method on the network without the
|
||||||
|
// possibility to miss a few first connection events.
|
||||||
|
once := make(chan struct{})
|
||||||
|
// Close once channel so that it can be read from in the event loop.
|
||||||
|
close(once)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case e := <-events:
|
||||||
|
// Detect only connection events.
|
||||||
|
if e.Type != EventTypeConn {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Detect only "connect" events of all connection events.
|
||||||
|
if !e.Conn.Up {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Check that the connection is from the snapshot.
|
||||||
|
for _, conn := range snap.Conns {
|
||||||
|
if conn.One == e.Conn.One && conn.Other == e.Conn.Other {
|
||||||
|
counter++
|
||||||
|
|
||||||
|
if counter == total {
|
||||||
|
// Signal that all nodes are connected.
|
||||||
|
close(allConnected)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-once:
|
||||||
|
// Set once to nil as nil channel never blocks forever.
|
||||||
|
// This ensures that this for loop never gets into this part
|
||||||
|
// of the code again.
|
||||||
|
once = nil
|
||||||
|
// Proceed with connecting the nodes, as we are ready to
|
||||||
|
// detect events.
|
||||||
|
close(eventLoopStarted)
|
||||||
|
case <-done:
|
||||||
|
// Load function returned, terminate this goroutine.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Do not proceed until the goroutine with the event loop actually is ready
|
||||||
|
// to receive events.
|
||||||
|
<-eventLoopStarted
|
||||||
|
|
||||||
|
// Start connecting.
|
||||||
for _, conn := range snap.Conns {
|
for _, conn := range snap.Conns {
|
||||||
|
|
||||||
if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up {
|
if !net.GetNode(conn.One).Up || !net.GetNode(conn.Other).Up {
|
||||||
|
|
@ -725,10 +800,18 @@ func (net *Network) Load(snap *Snapshot) error {
|
||||||
//so it would result in the snapshot `Load` to fail
|
//so it would result in the snapshot `Load` to fail
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := net.Connect(conn.One, conn.Other); err != nil {
|
if err := net.Connect(conn.One, conn.Other); err != nil && !strings.Contains(err.Error(), "already connected") {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
// Wait until all connections from the snapshot are established.
|
||||||
|
case <-allConnected:
|
||||||
|
// Make sure that we do not wait forever.
|
||||||
|
case <-time.After(120 * time.Second):
|
||||||
|
return errors.New("snapshot connections not established")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue