Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

netdeploy: allow simple local net topologies #5612

Merged
merged 3 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 34 additions & 19 deletions netdeploy/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
"github.com/algorand/go-algorand/daemon/algod/api/server/v2/generated/model"
"github.com/algorand/go-algorand/gen"
"github.com/algorand/go-algorand/libgoal"
"github.com/algorand/go-algorand/netdeploy/remote"
"github.com/algorand/go-algorand/nodecontrol"
"github.com/algorand/go-algorand/util"
"golang.org/x/exp/maps"
)

const configFileName = "network.json"
Expand All @@ -43,8 +45,8 @@
Name string `json:"Name,omitempty"`
// RelayDirs are directories where relays live (where we check for connection IP:Port)
// They are stored relative to root dir (e.g. "Primary")
RelayDirs []string `json:"RelayDirs,omitempty"`
TemplateFile string `json:"TemplateFile,omitempty"` // Template file used to create the network
RelayDirs []string `json:"RelayDirs,omitempty"`
Template NetworkTemplate `json:"Template,omitempty"` // Template file used to create the network
algorandskiy marked this conversation as resolved.
Show resolved Hide resolved
}

// Network represents an instance of a deployed network
Expand Down Expand Up @@ -108,6 +110,7 @@
return n, err
}
n.gen = template.Genesis
n.cfg.Template = template

Check warning on line 113 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L113

Added line #L113 was not covered by tests

err = n.Save(rootDir)
n.SetConsensus(binDir, consensus)
Expand Down Expand Up @@ -278,9 +281,9 @@

// Start Prime Relay and get its listening address

var peerAddressListBuilder strings.Builder
var relayAddress string
var err error
relayNameToAddress := map[string]string{}

Check warning on line 286 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L286

Added line #L286 was not covered by tests
for _, relayDir := range n.cfg.RelayDirs {
nodeFullPath := n.getNodeFullPath(relayDir)
nc := nodecontrol.MakeNodeController(binDir, nodeFullPath)
Expand All @@ -299,15 +302,10 @@
if err != nil {
return err
}

if peerAddressListBuilder.Len() != 0 {
peerAddressListBuilder.WriteString(";")
}
peerAddressListBuilder.WriteString(relayAddress)
relayNameToAddress[relayDir] = relayAddress

Check warning on line 305 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L305

Added line #L305 was not covered by tests
}

peerAddressList := peerAddressListBuilder.String()
err = n.startNodes(binDir, peerAddressList, redirectOutput)
err = n.startNodes(binDir, relayNameToAddress, redirectOutput)

Check warning on line 308 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L308

Added line #L308 was not covered by tests
return err
}

Expand Down Expand Up @@ -337,21 +335,38 @@
if err != nil {
continue
}
if strings.HasPrefix(relayAddress, "http://") {
relayAddress = relayAddress[7:]
}
peerAddresses = append(peerAddresses, relayAddress)
peerAddresses = append(peerAddresses, strings.TrimPrefix(relayAddress, "http://"))

Check warning on line 338 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L338

Added line #L338 was not covered by tests
}
return peerAddresses
}

func (n Network) startNodes(binDir, relayAddress string, redirectOutput bool) error {
args := nodecontrol.AlgodStartArgs{
PeerAddress: relayAddress,
RedirectOutput: redirectOutput,
ExitErrorCallback: n.nodeExitCallback,
func (n Network) startNodes(binDir string, relayNameToAddress map[string]string, redirectOutput bool) error {
allRelaysAddresses := strings.Join(maps.Values(relayNameToAddress), ";")

Check warning on line 344 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L343-L344

Added lines #L343 - L344 were not covered by tests

nodeConfigToEntry := make(map[string]remote.NodeConfigGoal, len(n.cfg.Template.Nodes))
for _, n := range n.cfg.Template.Nodes {
nodeConfigToEntry[n.Name] = n

Check warning on line 348 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L346-L348

Added lines #L346 - L348 were not covered by tests
}

for _, nodeDir := range n.nodeDirs {
args := nodecontrol.AlgodStartArgs{
PeerAddress: allRelaysAddresses,
RedirectOutput: redirectOutput,
ExitErrorCallback: n.nodeExitCallback,

Check warning on line 355 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L352-L355

Added lines #L352 - L355 were not covered by tests
}
if n, ok := nodeConfigToEntry[nodeDir]; ok && len(n.PeerList) > 0 {
relayNames := strings.Split(n.PeerList, ";")
algorandskiy marked this conversation as resolved.
Show resolved Hide resolved
var peerAddresses []string
for _, relayName := range relayNames {
relayAddress, ok := relayNameToAddress[relayName]
if !ok {
return fmt.Errorf("relay %s is not defined in the network", relayName)

Check warning on line 363 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L357-L363

Added lines #L357 - L363 were not covered by tests
}
peerAddresses = append(peerAddresses, relayAddress)

Check warning on line 365 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L365

Added line #L365 was not covered by tests
}
args.PeerAddress = strings.Join(peerAddresses, ";")

Check warning on line 367 in netdeploy/network.go

View check run for this annotation

Codecov / codecov/patch

netdeploy/network.go#L367

Added line #L367 was not covered by tests
}

nc := nodecontrol.MakeNodeController(binDir, n.getNodeFullPath(nodeDir))
_, err := nc.StartAlgod(args)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions netdeploy/networkTemplate.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,14 @@ func (t NetworkTemplate) Validate() error {
}

// Follow nodes cannot be relays
// Relays cannot have peer list
for _, cfg := range t.Nodes {
algorandskiy marked this conversation as resolved.
Show resolved Hide resolved
if cfg.IsRelay && isEnableFollowMode(cfg.ConfigJSONOverride) {
return fmt.Errorf("invalid template: follower nodes may not be relays")
}
if cfg.IsRelay && len(cfg.PeerList) > 0 {
return fmt.Errorf("invalid template: relays may not have a peer list")
}
}

if t.Genesis.DevMode && len(t.Nodes) != 1 {
Expand Down
63 changes: 63 additions & 0 deletions netdeploy/networkTemplates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func TestLoadMissingConfig(t *testing.T) {
a := require.New(t)

templateDir, err := filepath.Abs("../test/testdata/nettemplates")
a.NoError(err)
template, err := loadTemplate(filepath.Join(templateDir, "<invalidname>.json"))
a.Error(err)
a.Equal(template.Genesis.NetworkName, "")
Expand Down Expand Up @@ -102,6 +103,68 @@ func TestValidate(t *testing.T) {
template, _ = loadTemplate(filepath.Join(templateDir, "TwoNodesOneRelay1000Accounts.json"))
err = template.Validate()
a.NoError(err)

templateDir, _ = filepath.Abs("../test/testdata/nettemplates")
template, _ = loadTemplate(filepath.Join(templateDir, "FiveNodesTwoRelays.json"))
err = template.Validate()
a.NoError(err)
}

func TestPeerListValidate(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

devmodeGenesis := gen.GenesisData{
Wallets: []gen.WalletData{
{
Stake: 100,
},
},
}

t.Run("PeerList is optional", func(t *testing.T) {
t.Parallel()
tmpl := NetworkTemplate{
Genesis: devmodeGenesis,
Nodes: []remote.NodeConfigGoal{
{
IsRelay: true,
},
{
IsRelay: false,
},
},
}
require.NoError(t, tmpl.Validate())
})

t.Run("Relays cannot have PeerList", func(t *testing.T) {
t.Parallel()
tmpl := NetworkTemplate{
Genesis: devmodeGenesis,
Nodes: []remote.NodeConfigGoal{
{
IsRelay: true,
PeerList: "R2",
},
},
}
require.ErrorContains(t, tmpl.Validate(), "relays may not have a peer list")
})

t.Run("Non-relays might have PeerList", func(t *testing.T) {
t.Parallel()
tmpl := NetworkTemplate{
Genesis: devmodeGenesis,
Nodes: []remote.NodeConfigGoal{
{
IsRelay: false,
PeerList: "R2",
},
},
}
require.NoError(t, tmpl.Validate())
})
}

func TestDevModeValidate(t *testing.T) {
Expand Down
18 changes: 12 additions & 6 deletions netdeploy/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/gen"
"github.com/algorand/go-algorand/test/partitiontest"
)

Expand All @@ -34,16 +35,19 @@ func TestSaveNetworkCfg(t *testing.T) {
a := require.New(t)

cfg := NetworkCfg{
Name: "testName",
RelayDirs: []string{"testPND"},
TemplateFile: "testTemplate",
Name: "testName",
RelayDirs: []string{"testPND"},
Template: NetworkTemplate{
Genesis: gen.DefaultGenesis,
},
}

tmpFolder := t.TempDir()
cfgFile := filepath.Join(tmpFolder, configFileName)
err := saveNetworkCfg(cfg, cfgFile)
a.Nil(err)
cfg1, err := loadNetworkCfg(cfgFile)
a.NoError(err)
a.Equal(cfg, cfg1)
}

Expand All @@ -63,9 +67,11 @@ func TestSaveConsensus(t *testing.T) {

net := Network{
cfg: NetworkCfg{
Name: "testName",
RelayDirs: []string{relayDir},
TemplateFile: "testTemplate",
Name: "testName",
RelayDirs: []string{relayDir},
Template: NetworkTemplate{
Genesis: gen.DefaultGenesis,
},
},
nodeDirs: map[string]string{
"node1": nodeDir,
Expand Down
1 change: 1 addition & 0 deletions netdeploy/remote/nodeConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ type NodeConfigGoal struct {
Wallets []NodeWalletData
DeadlockDetection int `json:"-"`
ConfigJSONOverride string `json:",omitempty"` // Raw json to merge into config.json after other modifications are complete
PeerList string `json:",omitempty"` // Semicolon separated list of peers to connect to. Only applicable for non-relays
}
56 changes: 56 additions & 0 deletions test/testdata/nettemplates/FiveNodesTwoRelays.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"Genesis": {
"NetworkName": "tbd",
"LastPartKeyRound": 5000,
"Wallets": [
{
"Name": "LargeWallet",
"Stake": 85,
"Online": true
},
{
"Name": "SmallWallet",
"Stake": 10,
"Online": true
},
{
"Name": "NonPartWallet",
"Stake": 5,
"Online": true
}
]
},
"Nodes": [
{
"Name": "Relay1",
"IsRelay": true
},
{
"Name": "Relay2",
"IsRelay": true
},
{
"Name": "PartNode1",
"Wallets": [{
"Name": "LargeWallet",
"ParticipationOnly": true
}],
"PeerList": "Relay1;Relay2"
},
{
"Name": "PartNode2",
"Wallets": [{
"Name": "SmallWallet",
"ParticipationOnly": true
}],
"PeerList": "Relay2"
},
{
"Name": "NonPartNode",
"Wallets": [{
"Name": "NonPartWallet"
}],
"PeerList": "Relay1"
}
]
}