This repository was archived by the owner on Aug 2, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 111
cmd/swarm/swarm-snapshot: Swarm snapshot binary #1077
Closed
Closed
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
bb8c0ac
cmd/swarm/swarm-snapshot: add binary to create network snapshots
acud 8cc3fe6
cmd/swarm/swarm-snapshot: refactor and extend tests
janos fe1ddb0
p2p/simulations: remove unused triggerChecks func and fix linter
janos 186dd02
internal/cmdtest: raise the timeout for killing TestCmd
janos b226052
cmd/swarm/swarm-snapshot: add more comments and other minor adjustments
janos a208208
cmd/swarm/swarm-snapshot: remove redundant check in createSnapshot
janos a40801d
cmd/swarm/swarm-snapshot: change comment wording
janos 621e2b6
p2p/simulations: revert Simulation.Run from master
janos 8520825
cmd/swarm/swarm-snapshot: address pr comments
acud b866ba9
swarm/network/simulations/discovery: removed snapshot write to file
acud e37ade0
cmd/swarm/swarm-snapshot, swarm/network/simulations: removed redundan…
acud File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
// Copyright 2018 The go-ethereum Authors | ||
// This file is part of go-ethereum. | ||
// | ||
// go-ethereum is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// go-ethereum is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path" | ||
"path/filepath" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/log" | ||
"github.com/ethereum/go-ethereum/node" | ||
"github.com/ethereum/go-ethereum/p2p/simulations" | ||
"github.com/ethereum/go-ethereum/p2p/simulations/adapters" | ||
"github.com/ethereum/go-ethereum/swarm/network" | ||
"github.com/ethereum/go-ethereum/swarm/network/simulation" | ||
cli "gopkg.in/urfave/cli.v1" | ||
) | ||
|
||
// create is used as the entry function for "create" app command. | ||
func create(ctx *cli.Context) error { | ||
log.PrintOrigins(true) | ||
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(ctx.Int("verbosity")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) | ||
|
||
if len(ctx.Args()) < 1 { | ||
return errors.New("argument should be the filename to verify or write-to") | ||
} | ||
filename, err := touchPath(ctx.Args()[0]) | ||
if err != nil { | ||
return err | ||
} | ||
return createSnapshot(filename, ctx.Int("nodes"), strings.Split(ctx.String("services"), ",")) | ||
} | ||
|
||
// createSnapshot creates a new snapshot on filesystem with provided filename, | ||
// number of nodes and service names. | ||
func createSnapshot(filename string, nodes int, services []string) (err error) { | ||
log.Debug("create snapshot", "filename", filename, "nodes", nodes, "services", services) | ||
|
||
sim := simulation.New(map[string]simulation.ServiceFunc{ | ||
"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { | ||
addr := network.NewAddr(ctx.Config.Node()) | ||
kad := network.NewKademlia(addr.Over(), network.NewKadParams()) | ||
hp := network.NewHiveParams() | ||
hp.KeepAliveInterval = time.Duration(200) * time.Millisecond | ||
hp.Discovery = true // discovery must be enabled when creating a snapshot | ||
|
||
config := &network.BzzConfig{ | ||
OverlayAddr: addr.Over(), | ||
UnderlayAddr: addr.Under(), | ||
HiveParams: hp, | ||
} | ||
return network.NewBzz(config, kad, nil, nil, nil), nil, nil | ||
}, | ||
}) | ||
defer sim.Close() | ||
|
||
_, err = sim.AddNodes(nodes) | ||
if err != nil { | ||
return fmt.Errorf("add nodes: %v", err) | ||
} | ||
|
||
err = sim.Net.ConnectNodesRing(nil) | ||
if err != nil { | ||
return fmt.Errorf("connect nodes: %v", err) | ||
} | ||
|
||
ctx, cancelSimRun := context.WithTimeout(context.Background(), 2*time.Minute) | ||
defer cancelSimRun() | ||
if _, err := sim.WaitTillHealthy(ctx); err != nil { | ||
return fmt.Errorf("wait for healthy kademlia: %v", err) | ||
} | ||
|
||
var snap *simulations.Snapshot | ||
if len(services) > 0 { | ||
// If service names are provided, include them in the snapshot. | ||
// But, check if "bzz" service is not among them to remove it | ||
// form the snapshot as it exists on snapshot creation. | ||
var removeServices []string | ||
var wantBzz bool | ||
for _, s := range services { | ||
if s == "bzz" { | ||
wantBzz = true | ||
break | ||
} | ||
} | ||
if !wantBzz { | ||
removeServices = []string{"bzz"} | ||
} | ||
snap, err = sim.Net.SnapshotWithServices(services, removeServices) | ||
} else { | ||
snap, err = sim.Net.Snapshot() | ||
} | ||
if err != nil { | ||
return fmt.Errorf("create snapshot: %v", err) | ||
} | ||
jsonsnapshot, err := json.Marshal(snap) | ||
if err != nil { | ||
return fmt.Errorf("json encode snapshot: %v", err) | ||
} | ||
return ioutil.WriteFile(filename, jsonsnapshot, 0666) | ||
} | ||
|
||
// touchPath creates an empty file and all subdirectories | ||
// that are missing. | ||
func touchPath(filename string) (string, error) { | ||
acud marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if path.IsAbs(filename) { | ||
if _, err := os.Stat(filename); err == nil { | ||
// path exists, overwrite | ||
return filename, nil | ||
} | ||
} | ||
|
||
d, f := path.Split(filename) | ||
dir, err := filepath.Abs(filepath.Dir(os.Args[0])) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
_, err = os.Stat(path.Join(dir, filename)) | ||
if err == nil { | ||
// path exists, overwrite | ||
return filename, nil | ||
} | ||
|
||
dirPath := path.Join(dir, d) | ||
filePath := path.Join(dirPath, f) | ||
if d != "" { | ||
err = os.MkdirAll(dirPath, os.ModeDir) | ||
if err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
return filePath, nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// Copyright 2018 The go-ethereum Authors | ||
// This file is part of go-ethereum. | ||
// | ||
// go-ethereum is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// go-ethereum is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"sort" | ||
"strconv" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/p2p/simulations" | ||
) | ||
|
||
// TestSnapshotCreate is a high level e2e test that tests for snapshot generation. | ||
// It runs a few "create" commands with different flag values and loads generated | ||
// snapshot files to validate their content. | ||
func TestSnapshotCreate(t *testing.T) { | ||
for _, v := range []struct { | ||
name string | ||
nodes int | ||
services string | ||
}{ | ||
{ | ||
name: "defaults", | ||
}, | ||
{ | ||
name: "more nodes", | ||
nodes: defaultNodes + 5, | ||
}, | ||
{ | ||
name: "services", | ||
services: "stream,pss,zorglub", | ||
}, | ||
{ | ||
name: "services with bzz", | ||
services: "bzz,pss", | ||
}, | ||
} { | ||
t.Run(v.name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
file, err := ioutil.TempFile("", "swarm-snapshot") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer os.Remove(file.Name()) | ||
|
||
if err = file.Close(); err != nil { | ||
t.Error(err) | ||
} | ||
|
||
args := []string{"create"} | ||
if v.nodes > 0 { | ||
args = append(args, "--nodes", strconv.Itoa(v.nodes)) | ||
} | ||
if v.services != "" { | ||
args = append(args, "--services", v.services) | ||
} | ||
testCmd := runSnapshot(t, append(args, file.Name())...) | ||
|
||
testCmd.ExpectExit() | ||
if code := testCmd.ExitStatus(); code != 0 { | ||
t.Fatalf("command exit code %v, expected 0", code) | ||
} | ||
|
||
f, err := os.Open(file.Name()) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer func() { | ||
err := f.Close() | ||
if err != nil { | ||
t.Error("closing snapshot file", "err", err) | ||
} | ||
}() | ||
|
||
b, err := ioutil.ReadAll(f) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
var snap simulations.Snapshot | ||
err = json.Unmarshal(b, &snap) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
wantNodes := v.nodes | ||
if wantNodes == 0 { | ||
wantNodes = defaultNodes | ||
} | ||
janos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
gotNodes := len(snap.Nodes) | ||
if gotNodes != wantNodes { | ||
t.Errorf("got %v nodes, want %v", gotNodes, wantNodes) | ||
} | ||
|
||
if len(snap.Conns) == 0 { | ||
t.Error("no connections in a snapshot") | ||
} | ||
|
||
var wantServices []string | ||
if v.services != "" { | ||
wantServices = strings.Split(v.services, ",") | ||
} else { | ||
wantServices = []string{"bzz"} | ||
} | ||
// sort service names so they can be comparable | ||
// as strings to every node sorted services | ||
sort.Strings(wantServices) | ||
|
||
for i, n := range snap.Nodes { | ||
gotServices := n.Node.Config.Services | ||
sort.Strings(gotServices) | ||
if fmt.Sprint(gotServices) != fmt.Sprint(wantServices) { | ||
t.Errorf("got services %v for node %v, want %v", gotServices, i, wantServices) | ||
} | ||
} | ||
|
||
}) | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// Copyright 2018 The go-ethereum Authors | ||
// This file is part of go-ethereum. | ||
// | ||
// go-ethereum is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// go-ethereum is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/ethereum/go-ethereum/cmd/utils" | ||
"github.com/ethereum/go-ethereum/log" | ||
cli "gopkg.in/urfave/cli.v1" | ||
) | ||
|
||
var gitCommit string // Git SHA1 commit hash of the release (set via linker flags) | ||
|
||
// default value for "create" command --nodes flag | ||
const defaultNodes = 10 | ||
|
||
func main() { | ||
err := newApp().Run(os.Args) | ||
if err != nil { | ||
log.Error(err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
// newApp construct a new instance of Swarm Snapshot Utility. | ||
// Method Run is called on it in the main function and in tests. | ||
func newApp() (app *cli.App) { | ||
app = utils.NewApp(gitCommit, "Swarm Snapshot Utility") | ||
|
||
app.Name = "swarm-snapshot" | ||
app.Usage = "" | ||
|
||
// app flags (for all commands) | ||
app.Flags = []cli.Flag{ | ||
cli.IntFlag{ | ||
Name: "verbosity", | ||
Value: 1, | ||
Usage: "verbosity level", | ||
}, | ||
} | ||
|
||
app.Commands = []cli.Command{ | ||
{ | ||
Name: "create", | ||
Aliases: []string{"c"}, | ||
Usage: "create a swarm snapshot", | ||
Action: create, | ||
// Flags only for "create" command. | ||
// Allow app flags to be specified after the | ||
// command argument. | ||
Flags: append(app.Flags, | ||
cli.IntFlag{ | ||
Name: "nodes", | ||
Value: defaultNodes, | ||
Usage: "number of nodes", | ||
}, | ||
cli.StringFlag{ | ||
Name: "services", | ||
Value: "bzz", | ||
Usage: "comma separated list of services to boot the nodes with", | ||
}, | ||
), | ||
}, | ||
} | ||
|
||
return app | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.