Skip to content

Commit 598018b

Browse files
authored
tmpnet: Add a UUID to temporary networks to support metrics collection (#2763)
1 parent 4e2d005 commit 598018b

File tree

12 files changed

+73
-93
lines changed

12 files changed

+73
-93
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ concurrency:
2121

2222
env:
2323
go_version: '~1.21.8'
24-
tmpnet_data_path: ~/.tmpnet/networks/1000
24+
tmpnet_data_path: ~/.tmpnet/networks
2525

2626
jobs:
2727
Unit:

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
github.com/ethereum/go-ethereum v1.12.0
1919
github.com/google/btree v1.1.2
2020
github.com/google/renameio/v2 v2.0.0
21+
github.com/google/uuid v1.6.0
2122
github.com/gorilla/mux v1.8.0
2223
github.com/gorilla/rpc v1.2.0
2324
github.com/gorilla/websocket v1.4.2
@@ -99,7 +100,6 @@ require (
99100
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
100101
github.com/google/go-cmp v0.6.0 // indirect
101102
github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect
102-
github.com/google/uuid v1.6.0 // indirect
103103
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
104104
github.com/hashicorp/go-bexpr v0.1.10 // indirect
105105
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect

tests/e2e/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ $ ./scripts/build_tmpnetctl.sh
7777
# Start a new network
7878
$ ./build/tmpnetctl start-network --avalanchego-path=/path/to/avalanchego
7979
...
80-
Started network 1000 @ /home/me/.tmpnet/networks/1000
80+
Started network /home/me/.tmpnet/networks/20240306-152305.924531 (UUID: abaab590-b375-44f6-9ca5-f8a6dc061725)
8181

8282
Configure tmpnetctl and the test suite to target this network by default
8383
with one of the following statements:
84-
- source /home/me/.tmpnet/networks/1000/network.env
85-
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/1000
84+
- source /home/me/.tmpnet/networks/20240306-152305.924531/network.env
85+
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/20240306-152305.924531
8686
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/latest
8787

8888
# Start a new test run using the existing network

tests/e2e/c/dynamic_fees.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ var _ = e2e.DescribeCChain("[Dynamic Fees]", func() {
3737

3838
ginkgo.It("should ensure that the gas price is affected by load", func() {
3939
ginkgo.By("creating a new private network to ensure isolation from other tests")
40-
privateNetwork := e2e.Env.NewPrivateNetwork()
40+
privateNetwork := &tmpnet.Network{
41+
Owner: "avalanchego-e2e-dynamic-fees",
42+
}
43+
e2e.Env.StartPrivateNetwork(privateNetwork)
4144

4245
ginkgo.By("allocating a pre-funded key")
4346
key := privateNetwork.PreFundedKeys[0]

tests/e2e/e2e_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ func init() {
3535

3636
var _ = ginkgo.SynchronizedBeforeSuite(func() []byte {
3737
// Run only once in the first ginkgo process
38-
return e2e.NewTestEnvironment(flagVars, &tmpnet.Network{}).Marshal()
38+
return e2e.NewTestEnvironment(
39+
flagVars,
40+
&tmpnet.Network{
41+
Owner: "avalanchego-e2e",
42+
},
43+
).Marshal()
3944
}, func(envBytes []byte) {
4045
// Run in every ginkgo process
4146

tests/fixture/e2e/env.go

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ package e2e
66
import (
77
"encoding/json"
88
"math/rand"
9-
"os"
10-
"path/filepath"
119
"time"
1210

1311
"github.com/stretchr/testify/require"
@@ -18,7 +16,6 @@ import (
1816
"github.com/ava-labs/avalanchego/tests/fixture"
1917
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
2018
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
21-
"github.com/ava-labs/avalanchego/utils/perms"
2219
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
2320

2421
ginkgo "github.com/onsi/ginkgo/v2"
@@ -77,7 +74,7 @@ func NewTestEnvironment(flagVars *FlagVars, desiredNetwork *tmpnet.Network) *Tes
7774
}
7875
} else {
7976
network = desiredNetwork
80-
StartNetwork(network, DefaultNetworkDir, flagVars.AvalancheGoExecPath(), flagVars.PluginDir())
77+
StartNetwork(network, flagVars.AvalancheGoExecPath(), flagVars.PluginDir())
8178
}
8279

8380
// A new network will always need subnet creation and an existing
@@ -158,27 +155,17 @@ func (te *TestEnvironment) NewKeychain(count int) *secp256k1fx.Keychain {
158155
}
159156

160157
// Create a new private network that is not shared with other tests.
161-
func (te *TestEnvironment) NewPrivateNetwork() *tmpnet.Network {
162-
// Load the shared network to retrieve its path and exec path
158+
func (te *TestEnvironment) StartPrivateNetwork(network *tmpnet.Network) {
159+
// Use the same configuration as the shared network
163160
sharedNetwork, err := tmpnet.ReadNetwork(te.NetworkDir)
164161
te.require.NoError(err)
165162

166-
network := &tmpnet.Network{}
167-
168-
// The private networks dir is under the shared network dir to ensure it
169-
// will be included in the artifact uploaded in CI.
170-
privateNetworksDir := filepath.Join(sharedNetwork.Dir, PrivateNetworksDirName)
171-
te.require.NoError(os.MkdirAll(privateNetworksDir, perms.ReadWriteExecute))
172-
173163
pluginDir, err := sharedNetwork.DefaultFlags.GetStringVal(config.PluginDirKey)
174164
te.require.NoError(err)
175165

176166
StartNetwork(
177167
network,
178-
privateNetworksDir,
179168
sharedNetwork.DefaultRuntimeConfig.AvalancheGoPath,
180169
pluginDir,
181170
)
182-
183-
return network
184171
}

tests/fixture/e2e/helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,15 @@ func CheckBootstrapIsPossible(network *tmpnet.Network) {
216216
}
217217

218218
// Start a temporary network with the provided avalanchego binary.
219-
func StartNetwork(network *tmpnet.Network, rootNetworkDir string, avalancheGoExecPath string, pluginDir string) {
219+
func StartNetwork(network *tmpnet.Network, avalancheGoExecPath string, pluginDir string) {
220220
require := require.New(ginkgo.GinkgoT())
221221

222222
require.NoError(
223223
tmpnet.StartNewNetwork(
224224
DefaultContext(),
225225
ginkgo.GinkgoWriter,
226226
network,
227-
rootNetworkDir,
227+
DefaultNetworkDir,
228228
avalancheGoExecPath,
229229
pluginDir,
230230
tmpnet.DefaultNodeCount,

tests/fixture/tmpnet/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ $ ./scripts/build_tmpnetctl.sh
5252
# Start a new network
5353
$ ./build/tmpnetctl start-network --avalanchego-path=/path/to/avalanchego
5454
...
55-
Started network 1000 @ /home/me/.tmpnet/networks/1000
55+
Started network /home/me/.tmpnet/networks/20240306-152305.924531 (UUID: abaab590-b375-44f6-9ca5-f8a6dc061725)
5656

5757
Configure tmpnetctl to target this network by default with one of the following statements:
58-
- source /home/me/.tmpnet/networks/1000/network.env
59-
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/1000
58+
- source /home/me/.tmpnet/networks/20240306-152305.924531/network.env
59+
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/20240306-152305.924531
6060
- export TMPNET_NETWORK_DIR=/home/me/.tmpnet/networks/latest
6161

6262
# Stop the network
@@ -129,7 +129,7 @@ A temporary network relies on configuration written to disk in the following str
129129
HOME
130130
└── .tmpnet // Root path for the temporary network fixture
131131
└── networks // Default parent directory for temporary networks
132-
└── 1000 // The networkID is used to name the network dir and starts at 1000
132+
└── 20240306-152305.924531 // The timestamp of creation is the name of a network's directory
133133
├── NodeID-37E8UK3x2YFsHE3RdALmfWcppcZ1eTuj9 // The ID of a node is the name of its data dir
134134
│ ├── chainData
135135
│ │ └── ...

tests/fixture/tmpnet/cmd/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func main() {
4949

5050
var (
5151
rootDir string
52+
networkOwner string
5253
avalancheGoPath string
5354
pluginDir string
5455
nodeCount uint8
@@ -63,7 +64,9 @@ func main() {
6364

6465
// Root dir will be defaulted on start if not provided
6566

66-
network := &tmpnet.Network{}
67+
network := &tmpnet.Network{
68+
Owner: networkOwner,
69+
}
6770

6871
// Extreme upper bound, should never take this long
6972
networkStartTimeout := 2 * time.Minute
@@ -106,6 +109,7 @@ func main() {
106109
startNetworkCmd.PersistentFlags().StringVar(&avalancheGoPath, "avalanchego-path", os.Getenv(tmpnet.AvalancheGoPathEnvName), "The path to an avalanchego binary")
107110
startNetworkCmd.PersistentFlags().StringVar(&pluginDir, "plugin-dir", os.ExpandEnv("$HOME/.avalanchego/plugins"), "[optional] the dir containing VM plugins")
108111
startNetworkCmd.PersistentFlags().Uint8Var(&nodeCount, "node-count", tmpnet.DefaultNodeCount, "Number of nodes the network should initially consist of")
112+
startNetworkCmd.PersistentFlags().StringVar(&networkOwner, "network-owner", "", "The string identifying the intended owner of the network")
109113
rootCmd.AddCommand(startNetworkCmd)
110114

111115
stopNetworkCmd := &cobra.Command{

tests/fixture/tmpnet/network.go

Lines changed: 36 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ import (
99
"errors"
1010
"fmt"
1111
"io"
12-
"io/fs"
1312
"os"
1413
"path/filepath"
1514
"strconv"
1615
"strings"
1716
"time"
1817

18+
"github.com/google/uuid"
19+
1920
"github.com/ava-labs/avalanchego/config"
2021
"github.com/ava-labs/avalanchego/genesis"
2122
"github.com/ava-labs/avalanchego/ids"
22-
"github.com/ava-labs/avalanchego/utils/constants"
2323
"github.com/ava-labs/avalanchego/utils/crypto/secp256k1"
2424
"github.com/ava-labs/avalanchego/utils/perms"
2525
"github.com/ava-labs/avalanchego/utils/set"
@@ -40,6 +40,9 @@ const (
4040
// increase the time for a network's nodes to be seen as healthy.
4141
networkHealthCheckInterval = 200 * time.Millisecond
4242

43+
// All temporary networks will use this arbitrary network ID by default.
44+
defaultNetworkID = 88888
45+
4346
// eth address: 0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC
4447
HardHatKeyStr = "56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027"
4548
)
@@ -61,6 +64,16 @@ func init() {
6164

6265
// Collects the configuration for running a temporary avalanchego network
6366
type Network struct {
67+
// Uniquely identifies the temporary network for metrics
68+
// collection. Distinct from avalanchego's concept of network ID
69+
// since the utility of special network ID values (e.g. to trigger
70+
// specific fork behavior in a given network) precludes requiring
71+
// unique network ID values across all temporary networks.
72+
UUID string
73+
74+
// A string identifying the entity that started or maintains this network.
75+
Owner string
76+
6477
// Path where network configuration and data is stored
6578
Dir string
6679

@@ -150,6 +163,11 @@ func (n *Network) EnsureDefaultConfig(w io.Writer, avalancheGoPath string, plugi
150163
return err
151164
}
152165

166+
// A UUID supports centralized metrics collection
167+
if len(n.UUID) == 0 {
168+
n.UUID = uuid.NewString()
169+
}
170+
153171
// Ensure default flags
154172
if n.DefaultFlags == nil {
155173
n.DefaultFlags = FlagsMap{}
@@ -206,8 +224,9 @@ func (n *Network) EnsureDefaultConfig(w io.Writer, avalancheGoPath string, plugi
206224
return nil
207225
}
208226

209-
// Creates the network on disk, choosing its network id and generating its genesis in the process.
227+
// Creates the network on disk, generating its genesis and configuring its nodes in the process.
210228
func (n *Network) Create(rootDir string) error {
229+
// Ensure creation of the root dir
211230
if len(rootDir) == 0 {
212231
// Use the default root dir
213232
var err error
@@ -216,48 +235,34 @@ func (n *Network) Create(rootDir string) error {
216235
return err
217236
}
218237
}
219-
220-
// Ensure creation of the root dir
221238
if err := os.MkdirAll(rootDir, perms.ReadWriteExecute); err != nil {
222239
return fmt.Errorf("failed to create root network dir: %w", err)
223240
}
224241

225-
// Determine the network path and ID
226-
var (
227-
networkDir string
228-
networkID uint32
229-
)
230-
if n.Genesis != nil && n.Genesis.NetworkID > 0 {
231-
// Use the network ID defined in the provided genesis
232-
networkID = n.Genesis.NetworkID
242+
// A time-based name ensures consistent directory ordering
243+
dirName := time.Now().Format("20060102-150405.999999")
244+
if len(n.Owner) > 0 {
245+
// Include the owner to differentiate networks created at similar times
246+
dirName = fmt.Sprintf("%s-%s", dirName, n.Owner)
233247
}
234-
if networkID > 0 {
235-
// Use a directory with a random suffix
236-
var err error
237-
networkDir, err = os.MkdirTemp(rootDir, fmt.Sprintf("%d.", n.Genesis.NetworkID))
238-
if err != nil {
239-
return fmt.Errorf("failed to create network dir: %w", err)
240-
}
241-
} else {
242-
// Find the next available network ID based on the contents of the root dir
243-
var err error
244-
networkID, networkDir, err = findNextNetworkID(rootDir)
245-
if err != nil {
246-
return err
247-
}
248+
249+
// Ensure creation of the network dir
250+
networkDir := filepath.Join(rootDir, dirName)
251+
if err := os.MkdirAll(networkDir, perms.ReadWriteExecute); err != nil {
252+
return fmt.Errorf("failed to create network dir: %w", err)
248253
}
249254
canonicalDir, err := toCanonicalDir(networkDir)
250255
if err != nil {
251256
return err
252257
}
253258
n.Dir = canonicalDir
254259

260+
// Ensure the existence of the plugin directory or nodes won't be able to start.
255261
pluginDir, err := n.DefaultFlags.GetStringVal(config.PluginDirKey)
256262
if err != nil {
257263
return err
258264
}
259265
if len(pluginDir) > 0 {
260-
// Ensure the existence of the plugin directory or nodes won't be able to start.
261266
if err := os.MkdirAll(pluginDir, perms.ReadWriteExecute); err != nil {
262267
return fmt.Errorf("failed to create plugin dir: %w", err)
263268
}
@@ -275,7 +280,7 @@ func (n *Network) Create(rootDir string) error {
275280
}
276281
keysToFund = append(keysToFund, n.PreFundedKeys...)
277282

278-
genesis, err := NewTestGenesis(networkID, n.Nodes, keysToFund)
283+
genesis, err := NewTestGenesis(defaultNetworkID, n.Nodes, keysToFund)
279284
if err != nil {
280285
return err
281286
}
@@ -296,7 +301,7 @@ func (n *Network) Create(rootDir string) error {
296301

297302
// Starts all nodes in the network
298303
func (n *Network) Start(ctx context.Context, w io.Writer) error {
299-
if _, err := fmt.Fprintf(w, "Starting network %d @ %s\n", n.Genesis.NetworkID, n.Dir); err != nil {
304+
if _, err := fmt.Fprintf(w, "Starting network %s (UUID: %s)\n", n.Dir, n.UUID); err != nil {
300305
return err
301306
}
302307

@@ -313,7 +318,7 @@ func (n *Network) Start(ctx context.Context, w io.Writer) error {
313318
if err := n.WaitForHealthy(ctx, w); err != nil {
314319
return err
315320
}
316-
if _, err := fmt.Fprintf(w, "\nStarted network %d @ %s\n", n.Genesis.NetworkID, n.Dir); err != nil {
321+
if _, err := fmt.Fprintf(w, "\nStarted network %s (UUID: %s)\n", n.Dir, n.UUID); err != nil {
317322
return err
318323
}
319324

@@ -676,33 +681,3 @@ func getDefaultRootDir() (string, error) {
676681
}
677682
return filepath.Join(homeDir, ".tmpnet", "networks"), nil
678683
}
679-
680-
// Finds the next available network ID by attempting to create a
681-
// directory numbered from 1000 until creation succeeds. Returns the
682-
// network id and the full path of the created directory.
683-
func findNextNetworkID(rootDir string) (uint32, string, error) {
684-
var (
685-
networkID uint32 = 1000
686-
dirPath string
687-
)
688-
for {
689-
_, reserved := constants.NetworkIDToNetworkName[networkID]
690-
if reserved {
691-
networkID++
692-
continue
693-
}
694-
695-
dirPath = filepath.Join(rootDir, strconv.FormatUint(uint64(networkID), 10))
696-
err := os.Mkdir(dirPath, perms.ReadWriteExecute)
697-
if err == nil {
698-
return networkID, dirPath, nil
699-
}
700-
701-
if !errors.Is(err, fs.ErrExist) {
702-
return 0, "", fmt.Errorf("failed to create network directory: %w", err)
703-
}
704-
705-
// Directory already exists, keep iterating
706-
networkID++
707-
}
708-
}

0 commit comments

Comments
 (0)