Skip to content

Commit b5d8d9d

Browse files
committed
[tmpnet] Avoid serializing the node data directory
This is intended to simplify usage by CLI.
1 parent 0ccb028 commit b5d8d9d

File tree

11 files changed

+91
-130
lines changed

11 files changed

+91
-130
lines changed

tests/antithesis/init_db.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func initBootstrapDB(network *tmpnet.Network, destPath string) error {
4545
}
4646

4747
// Copy the db state from the bootstrap node to the compose volume path.
48-
sourcePath := filepath.Join(network.Nodes[0].GetDataDir(), "db")
48+
sourcePath := filepath.Join(network.Nodes[0].DataDir, "db")
4949
if err := os.MkdirAll(destPath, perms.ReadWriteExecute); err != nil {
5050
return fmt.Errorf("failed to create db path %q: %w", destPath, err)
5151
}

tests/e2e/faultinjection/duplicate_node_id.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package faultinjection
55

66
import (
77
"context"
8-
"fmt"
8+
"path/filepath"
99

1010
"github.com/onsi/ginkgo/v2"
1111
"github.com/stretchr/testify/require"
@@ -27,23 +27,22 @@ var _ = ginkgo.Describe("Duplicate node handling", func() {
2727
network := e2e.GetEnv(tc).GetNetwork()
2828

2929
tc.By("creating new node")
30-
node1 := e2e.AddEphemeralNode(tc, network, tmpnet.FlagsMap{})
30+
node1 := e2e.AddEphemeralNode(tc, network, tmpnet.NewEphemeralNode(tmpnet.FlagsMap{}))
3131
e2e.WaitForHealthy(tc, node1)
3232

3333
tc.By("checking that the new node is connected to its peers")
3434
checkConnectedPeers(tc, network.Nodes, node1)
3535

3636
tc.By("creating a second new node with the same staking keypair as the first new node")
37-
node1Flags := node1.Flags
38-
node2Flags := tmpnet.FlagsMap{
39-
config.StakingTLSKeyContentKey: node1Flags[config.StakingTLSKeyContentKey],
40-
config.StakingCertContentKey: node1Flags[config.StakingCertContentKey],
41-
// Construct a unique data dir to ensure the two nodes' data will be stored
42-
// separately. Usually the dir name is the node ID but in this one case the nodes have
43-
// the same node ID.
44-
config.DataDirKey: fmt.Sprintf("%s-second", node1Flags[config.DataDirKey]),
45-
}
46-
node2 := e2e.AddEphemeralNode(tc, network, node2Flags)
37+
node2 := tmpnet.NewEphemeralNode(tmpnet.FlagsMap{
38+
config.StakingTLSKeyContentKey: node1.Flags[config.StakingTLSKeyContentKey],
39+
config.StakingCertContentKey: node1.Flags[config.StakingCertContentKey],
40+
})
41+
// Construct a unique data dir to ensure the two nodes' data will be stored
42+
// separately. Usually the dir name is the node ID but in this one case the nodes have
43+
// the same node ID.
44+
node2.DataDir = filepath.Join(network.Dir, node1.DataDir+"second")
45+
_ = e2e.AddEphemeralNode(tc, network, node2)
4746

4847
tc.By("checking that the second new node fails to become healthy before timeout")
4948
err := tmpnet.WaitForHealthy(tc.DefaultContext(), node2)

tests/e2e/p/interchain_workflow.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ var _ = e2e.DescribePChain("[Interchain Workflow]", ginkgo.Label(e2e.UsesCChainL
108108
})
109109

110110
tc.By("adding new node and waiting for it to report healthy")
111-
node := e2e.AddEphemeralNode(tc, network, tmpnet.FlagsMap{})
111+
node := e2e.AddEphemeralNode(tc, network, tmpnet.NewEphemeralNode(tmpnet.FlagsMap{}))
112112
e2e.WaitForHealthy(tc, node)
113113

114114
tc.By("retrieving new node's id and pop")

tests/e2e/p/l1.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ var _ = e2e.DescribePChain("[L1]", func() {
172172
})
173173

174174
tc.By("creating the genesis validator")
175-
subnetGenesisNode := e2e.AddEphemeralNode(tc, env.GetNetwork(), tmpnet.FlagsMap{
175+
subnetGenesisNode := e2e.AddEphemeralNode(tc, env.GetNetwork(), tmpnet.NewEphemeralNode(tmpnet.FlagsMap{
176176
config.TrackSubnetsKey: subnetID.String(),
177-
})
177+
}))
178178

179179
genesisNodePoP, err := subnetGenesisNode.GetProofOfPossession()
180180
require.NoError(err)
@@ -348,9 +348,9 @@ var _ = e2e.DescribePChain("[L1]", func() {
348348
tc.By("advancing the proposervm P-chain height", advanceProposerVMPChainHeight)
349349

350350
tc.By("creating the validator to register")
351-
subnetRegisterNode := e2e.AddEphemeralNode(tc, env.GetNetwork(), tmpnet.FlagsMap{
351+
subnetRegisterNode := e2e.AddEphemeralNode(tc, env.GetNetwork(), tmpnet.NewEphemeralNode(tmpnet.FlagsMap{
352352
config.TrackSubnetsKey: subnetID.String(),
353-
})
353+
}))
354354

355355
registerNodePoP, err := subnetRegisterNode.GetProofOfPossession()
356356
require.NoError(err)

tests/e2e/p/staking_rewards.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ var _ = ginkgo.Describe("[Staking Rewards]", func() {
5555
})
5656

5757
tc.By("adding alpha node, whose uptime should result in a staking reward")
58-
alphaNode := e2e.AddEphemeralNode(tc, network, tmpnet.FlagsMap{})
58+
alphaNode := e2e.AddEphemeralNode(tc, network, tmpnet.NewEphemeralNode(tmpnet.FlagsMap{}))
5959
tc.By("adding beta node, whose uptime should not result in a staking reward")
60-
betaNode := e2e.AddEphemeralNode(tc, network, tmpnet.FlagsMap{})
60+
betaNode := e2e.AddEphemeralNode(tc, network, tmpnet.NewEphemeralNode(tmpnet.FlagsMap{}))
6161

6262
// Wait to check health until both nodes have started to minimize the duration
6363
// required for both nodes to report healthy.

tests/fixture/e2e/helpers.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,9 @@ func NewEthClient(tc tests.TestContext, nodeURI tmpnet.NodeURI) ethclient.Client
133133
}
134134

135135
// Adds an ephemeral node intended to be used by a single test.
136-
func AddEphemeralNode(tc tests.TestContext, network *tmpnet.Network, flags tmpnet.FlagsMap) *tmpnet.Node {
136+
func AddEphemeralNode(tc tests.TestContext, network *tmpnet.Network, node *tmpnet.Node) *tmpnet.Node {
137137
require := require.New(tc)
138138

139-
node := tmpnet.NewEphemeralNode(flags)
140139
require.NoError(network.StartNode(tc.DefaultContext(), tc.Log(), node))
141140

142141
tc.DeferCleanup(func() {

tests/fixture/tmpnet/network.go

Lines changed: 23 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,6 @@ func (n *Network) EnsureDefaultConfig(log logging.Logger) error {
240240
n.PrimaryChainConfigs[alias].SetDefaults(chainConfig)
241241
}
242242

243-
// Ensure nodes are configured
244-
for i := range n.Nodes {
245-
if err := n.EnsureNodeConfig(n.Nodes[i]); err != nil {
246-
return err
247-
}
248-
}
249-
250243
return nil
251244
}
252245

@@ -504,23 +497,22 @@ func (n *Network) RestartNode(ctx context.Context, log logging.Logger, node *Nod
504497

505498
// Stops all nodes in the network.
506499
func (n *Network) Stop(ctx context.Context) error {
507-
// Target all nodes, including the ephemeral ones
508-
nodes, err := ReadNodes(n, true /* includeEphemeral */)
509-
if err != nil {
500+
// Ensure the node state is up-to-date
501+
if err := n.readNodes(); err != nil {
510502
return err
511503
}
512504

513505
var errs []error
514506

515507
// Initiate stop on all nodes
516-
for _, node := range nodes {
508+
for _, node := range n.Nodes {
517509
if err := node.InitiateStop(ctx); err != nil {
518510
errs = append(errs, fmt.Errorf("failed to stop node %s: %w", node.NodeID, err))
519511
}
520512
}
521513

522514
// Wait for stop to complete on all nodes
523-
for _, node := range nodes {
515+
for _, node := range n.Nodes {
524516
if err := node.WaitForStopped(ctx); err != nil {
525517
errs = append(errs, fmt.Errorf("failed to wait for node %s to stop: %w", node.NodeID, err))
526518
}
@@ -554,14 +546,9 @@ func (n *Network) EnsureNodeConfig(node *Node) error {
554546
return err
555547
}
556548

557-
if len(n.Dir) > 0 {
558-
// Ensure the node's data dir is configured
559-
dataDir := node.GetDataDir()
560-
if len(dataDir) == 0 {
561-
// NodeID will have been set by EnsureKeys
562-
dataDir = filepath.Join(n.Dir, node.NodeID.String())
563-
node.Flags[config.DataDirKey] = dataDir
564-
}
549+
// Ensure a data directory if not already set
550+
if len(node.DataDir) == 0 {
551+
node.DataDir = filepath.Join(n.Dir, node.NodeID.String())
565552
}
566553

567554
return nil
@@ -768,16 +755,13 @@ func (n *Network) GetNodeURIs() []NodeURI {
768755
// collecting the bootstrap details for restarting a node).
769756
// For consumption outside of avalanchego. Needs to be kept exported.
770757
func (n *Network) GetBootstrapIPsAndIDs(skippedNode *Node) ([]string, []string, error) {
771-
// Collect staking addresses of non-ephemeral nodes for use in bootstrapping a node
772-
nodes, err := ReadNodes(n, false /* includeEphemeral */)
773-
if err != nil {
774-
return nil, nil, fmt.Errorf("failed to read network's nodes: %w", err)
775-
}
776-
var (
777-
bootstrapIPs = make([]string, 0, len(nodes))
778-
bootstrapIDs = make([]string, 0, len(nodes))
779-
)
780-
for _, node := range nodes {
758+
bootstrapIPs := []string{}
759+
bootstrapIDs := []string{}
760+
for _, node := range n.Nodes {
761+
if node.IsEphemeral {
762+
// Ephemeral nodes are not guaranteed to stay running
763+
continue
764+
}
781765
if skippedNode != nil && node.NodeID == skippedNode.NodeID {
782766
continue
783767
}
@@ -940,12 +924,16 @@ func (n *Network) writeNodeFlags(log logging.Logger, node *Node) error {
940924
// Only configure the plugin dir with a non-empty value to ensure the use of
941925
// the default value (`[datadir]/plugins`) when no plugin dir is configured.
942926
processConfig := node.getRuntimeConfig().Process
943-
if processConfig != nil && len(processConfig.PluginDir) > 0 {
944-
// Ensure the plugin directory exists or the node will fail to start
945-
if err := os.MkdirAll(processConfig.PluginDir, perms.ReadWriteExecute); err != nil {
946-
return fmt.Errorf("failed to create plugin dir: %w", err)
927+
if processConfig != nil {
928+
if len(processConfig.PluginDir) > 0 {
929+
// Ensure the plugin directory exists or the node will fail to start
930+
if err := os.MkdirAll(processConfig.PluginDir, perms.ReadWriteExecute); err != nil {
931+
return fmt.Errorf("failed to create plugin dir: %w", err)
932+
}
933+
flags.SetDefault(config.PluginDirKey, processConfig.PluginDir)
947934
}
948-
flags.SetDefault(config.PluginDirKey, processConfig.PluginDir)
935+
936+
flags.SetDefault(config.DataDirKey, node.DataDir)
949937
}
950938

951939
// Set the network and tmpnet defaults last to ensure they can be overridden

tests/fixture/tmpnet/network_config.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,35 @@ func (n *Network) readNetwork() error {
5757
return n.readConfig()
5858
}
5959

60-
// Read the non-ephemeral nodes associated with the network from disk.
60+
// Read the nodes associated with the network from disk.
6161
func (n *Network) readNodes() error {
62-
nodes, err := ReadNodes(n, false /* includeEphemeral */)
62+
nodes := []*Node{}
63+
64+
// Node configuration is stored in child directories
65+
entries, err := os.ReadDir(n.Dir)
6366
if err != nil {
64-
return err
67+
return fmt.Errorf("failed to read dir: %w", err)
6568
}
69+
for _, entry := range entries {
70+
if !entry.IsDir() {
71+
continue
72+
}
73+
74+
node := NewNode()
75+
dataDir := filepath.Join(n.Dir, entry.Name())
76+
err := node.Read(n, dataDir)
77+
if errors.Is(err, os.ErrNotExist) {
78+
// If no config file exists, assume this is not the path of a node
79+
continue
80+
} else if err != nil {
81+
return err
82+
}
83+
84+
nodes = append(nodes, node)
85+
}
86+
6687
n.Nodes = nodes
88+
6789
return nil
6890
}
6991

tests/fixture/tmpnet/node.go

Lines changed: 7 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,14 @@ package tmpnet
66
import (
77
"context"
88
"encoding/base64"
9-
"errors"
109
"fmt"
1110
"io"
1211
"net"
1312
"net/http"
1413
"net/netip"
15-
"os"
16-
"path/filepath"
1714
"strings"
1815
"time"
1916

20-
"github.com/spf13/cast"
21-
2217
"github.com/ava-labs/avalanchego/config"
2318
"github.com/ava-labs/avalanchego/ids"
2419
"github.com/ava-labs/avalanchego/staking"
@@ -83,25 +78,25 @@ type Node struct {
8378
URI string
8479
StakingAddress netip.AddrPort
8580

81+
// Defaults to [network dir]/[node id] if not set
82+
DataDir string
83+
8684
// Initialized on demand
8785
runtime NodeRuntime
8886

89-
// Intended to be set by the network
9087
network *Network
9188
}
9289

9390
// Initializes a new node with only the data dir set
94-
func NewNode(dataDir string) *Node {
91+
func NewNode() *Node {
9592
return &Node{
96-
Flags: FlagsMap{
97-
config.DataDirKey: dataDir,
98-
},
93+
Flags: FlagsMap{},
9994
}
10095
}
10196

10297
// Initializes an ephemeral node using the provided config flags
10398
func NewEphemeralNode(flags FlagsMap) *Node {
104-
node := NewNode("")
99+
node := NewNode()
105100
node.Flags = flags
106101
node.IsEphemeral = true
107102

@@ -112,7 +107,7 @@ func NewEphemeralNode(flags FlagsMap) *Node {
112107
func NewNodesOrPanic(count int) []*Node {
113108
nodes := make([]*Node, count)
114109
for i := range nodes {
115-
node := NewNode("")
110+
node := NewNode()
116111
if err := node.EnsureKeys(); err != nil {
117112
panic(err)
118113
}
@@ -121,51 +116,6 @@ func NewNodesOrPanic(count int) []*Node {
121116
return nodes
122117
}
123118

124-
// Reads a node's configuration from the specified directory.
125-
func ReadNode(dataDir string) (*Node, error) {
126-
node := NewNode(dataDir)
127-
return node, node.Read()
128-
}
129-
130-
// Reads nodes from the specified network directory.
131-
func ReadNodes(network *Network, includeEphemeral bool) ([]*Node, error) {
132-
nodes := []*Node{}
133-
134-
// Node configuration is stored in child directories
135-
entries, err := os.ReadDir(network.Dir)
136-
if err != nil {
137-
return nil, fmt.Errorf("failed to read dir: %w", err)
138-
}
139-
for _, entry := range entries {
140-
if !entry.IsDir() {
141-
continue
142-
}
143-
144-
nodeDir := filepath.Join(network.Dir, entry.Name())
145-
node, err := ReadNode(nodeDir)
146-
if errors.Is(err, os.ErrNotExist) {
147-
// If no config file exists, assume this is not the path of a node
148-
continue
149-
} else if err != nil {
150-
return nil, err
151-
}
152-
153-
if !includeEphemeral && node.IsEphemeral {
154-
continue
155-
}
156-
157-
if err := node.EnsureNodeID(); err != nil {
158-
return nil, fmt.Errorf("failed to ensure NodeID: %w", err)
159-
}
160-
161-
node.network = network
162-
163-
nodes = append(nodes, node)
164-
}
165-
166-
return nodes, nil
167-
}
168-
169119
// Retrieves the runtime for the node.
170120
func (n *Node) getRuntime() NodeRuntime {
171121
if n.runtime == nil {
@@ -210,10 +160,6 @@ func (n *Node) readState() error {
210160
return n.getRuntime().readState()
211161
}
212162

213-
func (n *Node) GetDataDir() string {
214-
return cast.ToString(n.Flags[config.DataDirKey])
215-
}
216-
217163
func (n *Node) GetLocalURI(ctx context.Context) (string, func(), error) {
218164
return n.getRuntime().GetLocalURI(ctx)
219165
}

0 commit comments

Comments
 (0)