diff --git a/kurtosis-devnet/pkg/kurtosis/kurtosis.go b/kurtosis-devnet/pkg/kurtosis/kurtosis.go index 475daf2cfbdfb..5767fc8d69c63 100644 --- a/kurtosis-devnet/pkg/kurtosis/kurtosis.go +++ b/kurtosis-devnet/pkg/kurtosis/kurtosis.go @@ -28,6 +28,7 @@ type Chain struct { Services EndpointMap `json:"services,omitempty"` Nodes []Node `json:"nodes"` Addresses deployer.DeploymentAddresses `json:"addresses,omitempty"` + Wallets WalletMap `json:"wallets,omitempty"` } type Wallet struct { @@ -39,9 +40,8 @@ type WalletMap map[string]Wallet // KurtosisEnvironment represents the output of a Kurtosis deployment type KurtosisEnvironment struct { - L1 *Chain `json:"l1"` - L2 []*Chain `json:"l2"` - Wallets WalletMap `json:"wallets"` + L1 *Chain `json:"l1"` + L2 []*Chain `json:"l2"` } // KurtosisDeployer handles deploying packages using Kurtosis @@ -164,8 +164,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En } env := &KurtosisEnvironment{ - L2: make([]*Chain, 0, len(spec.Chains)), - Wallets: d.getWallets(deployerState.Wallets), + L2: make([]*Chain, 0, len(spec.Chains)), } // Find L1 endpoint @@ -178,6 +177,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En } if deployerState.State != nil { chain.Addresses = deployerState.State.Addresses + chain.Wallets = d.getWallets(deployerState.Wallets) } env.L1 = chain } @@ -196,7 +196,10 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En // Add contract addresses if available if deployerState.State != nil && deployerState.State.Deployments != nil { if addresses, ok := deployerState.State.Deployments[chainSpec.NetworkID]; ok { - chain.Addresses = addresses + chain.Addresses = addresses.Addresses + } + if wallets, ok := deployerState.State.Deployments[chainSpec.NetworkID]; ok { + chain.Wallets = d.getWallets(wallets.Wallets) } } diff --git a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go index 3c5f6d3394d25..4b090eef90a29 100644 --- a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go +++ b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "math/big" - "os/exec" "strings" ) @@ -25,9 +24,14 @@ type DeploymentAddresses map[string]string // DeploymentStateAddresses maps chain IDs to their contract addresses type DeploymentStateAddresses map[string]DeploymentAddresses +type DeploymentState struct { + Addresses DeploymentAddresses `json:"addresses"` + Wallets WalletList `json:"wallets"` +} + type DeployerState struct { - Deployments DeploymentStateAddresses `json:"l2s"` - Addresses DeploymentAddresses `json:"superchain"` + Deployments map[string]DeploymentState `json:"l2s"` + Addresses DeploymentAddresses `json:"superchain"` } // StateFile represents the structure of the state.json file @@ -111,7 +115,9 @@ func NewDeployer(enclave string, opts ...DeployerOption) *Deployer { } // parseWalletsFile parses a JSON file containing wallet information -func parseWalletsFile(r io.Reader) (WalletList, error) { +func parseWalletsFile(r io.Reader) (map[string]WalletList, error) { + result := make(map[string]WalletList) + // Read all data from reader data, err := io.ReadAll(r) if err != nil { @@ -119,54 +125,48 @@ func parseWalletsFile(r io.Reader) (WalletList, error) { } // Unmarshal into a map first - var rawData map[string]string + var rawData map[string]map[string]string if err := json.Unmarshal(data, &rawData); err != nil { return nil, fmt.Errorf("failed to decode wallet file: %w", err) } - // Create a map to store wallets by name - walletMap := make(map[string]Wallet) - - // Process each key-value pair - for key, value := range rawData { - if strings.HasSuffix(key, "Address") { - name := strings.TrimSuffix(key, "Address") - wallet := walletMap[name] - wallet.Address = value - wallet.Name = name - walletMap[name] = wallet - } else if strings.HasSuffix(key, "PrivateKey") { - name := strings.TrimSuffix(key, "PrivateKey") - wallet := walletMap[name] - wallet.PrivateKey = value - wallet.Name = name - walletMap[name] = wallet + for id, chain := range rawData { + // Create a map to store wallets by name + walletMap := make(map[string]Wallet) + + // Process each key-value pair + for key, value := range chain { + if strings.HasSuffix(key, "Address") { + name := strings.TrimSuffix(key, "Address") + wallet := walletMap[name] + wallet.Address = value + wallet.Name = name + walletMap[name] = wallet + } else if strings.HasSuffix(key, "PrivateKey") { + name := strings.TrimSuffix(key, "PrivateKey") + wallet := walletMap[name] + wallet.PrivateKey = value + wallet.Name = name + walletMap[name] = wallet + } } - } - // Convert map to list - result := make(WalletList, 0, len(walletMap)) + // Convert map to list + wl := make(WalletList, 0, len(walletMap)) - for _, wallet := range walletMap { - // Only include wallets that have at least an address - if wallet.Address != "" { - result = append(result, &wallet) + for _, wallet := range walletMap { + // Only include wallets that have at least an address + if wallet.Address != "" { + wl = append(wl, &wallet) + } } + + result[id] = wl } return result, nil } -// downloadArtifact downloads a kurtosis artifact to a temporary directory -// TODO: reimplement this using the kurtosis SDK -func downloadArtifact(enclave, artifact, destDir string) error { - cmd := exec.Command("kurtosis", "files", "download", enclave, artifact, destDir) - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to download artifact %s: %w", artifact, err) - } - return nil -} - // hexToDecimal converts a hex string (with or without 0x prefix) to a decimal string func hexToDecimal(hex string) (string, error) { // Remove 0x prefix if present @@ -190,7 +190,7 @@ func parseStateFile(r io.Reader) (*DeployerState, error) { } result := &DeployerState{ - Deployments: make(DeploymentStateAddresses), + Deployments: make(map[string]DeploymentState), Addresses: make(DeploymentAddresses), } @@ -225,7 +225,9 @@ func parseStateFile(r io.Reader) (*DeployerState, error) { addresses := mapDeployment(deployment) if len(addresses) > 0 { - result.Deployments[id] = addresses + result.Deployments[id] = DeploymentState{ + Addresses: addresses, + } } } @@ -269,12 +271,17 @@ func (d *Deployer) ExtractData(ctx context.Context) (*DeployerData, error) { return nil, err } + for id, wallets := range wallets { + if deployment, exists := state.Deployments[id]; exists { + deployment.Wallets = wallets + state.Deployments[id] = deployment + } + } + knownWallets, err := d.getKnownWallets(ctx, fs) if err != nil { return nil, err } - wallets = append(wallets, knownWallets...) - - return &DeployerData{State: state, Wallets: wallets}, nil + return &DeployerData{State: state, Wallets: knownWallets}, nil } diff --git a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go index 9825bcbb81702..94720e532181d 100644 --- a/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go +++ b/kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go @@ -1,7 +1,6 @@ package deployer import ( - "os" "sort" "strings" "testing" @@ -67,7 +66,7 @@ func TestParseStateFile(t *testing.T) { require.True(t, ok, "Chain %s not found in result", tt.chainID) for key, expected := range tt.expected { - actual := chain[key] + actual := chain.Addresses[key] require.Equal(t, expected, actual, "Chain %s, %s: expected %s, got %s", tt.chainID, key, expected, actual) } } @@ -138,56 +137,52 @@ func TestParseStateFileErrors(t *testing.T) { } } -func TestDownloadArtifact(t *testing.T) { - // Create a temporary directory for testing - tmpDir, err := os.MkdirTemp("", "test-artifact-*") - require.NoError(t, err, "Failed to create temp dir") - defer os.RemoveAll(tmpDir) - - // Test with invalid enclave - err = downloadArtifact("invalid-enclave", "invalid-artifact", tmpDir) - require.Error(t, err, "Expected error for invalid enclave") -} - func TestParseWalletsFile(t *testing.T) { tests := []struct { name string input string - want WalletList + want map[string]WalletList wantErr bool }{ { name: "successful parse", input: `{ - "proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", - "proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", - "batcherPrivateKey": "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", - "batcherAddress": "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11" + "chain1": { + "proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", + "proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", + "batcherPrivateKey": "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", + "batcherAddress": "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11" + } }`, - want: WalletList{ - { - Name: "proposer", - Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", - PrivateKey: "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", - }, - { - Name: "batcher", - Address: "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11", - PrivateKey: "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", + want: map[string]WalletList{ + "chain1": { + { + Name: "proposer", + Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", + PrivateKey: "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", + }, + { + Name: "batcher", + Address: "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11", + PrivateKey: "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", + }, }, }, - wantErr: false, }, { name: "address only", input: `{ - "proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F" + "chain1": { + "proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F" + } }`, - want: WalletList{ - { - Name: "proposer", - Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", + want: map[string]WalletList{ + "chain1": { + { + Name: "proposer", + Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", + }, }, }, wantErr: false, @@ -195,9 +190,13 @@ func TestParseWalletsFile(t *testing.T) { { name: "private key only - should be ignored", input: `{ - "proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531" + "chain1": { + "proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531" + } }`, - want: WalletList{}, + want: map[string]WalletList{ + "chain1": {}, + }, wantErr: false, }, { @@ -209,7 +208,7 @@ func TestParseWalletsFile(t *testing.T) { { name: "empty input", input: `{}`, - want: WalletList{}, + want: map[string]WalletList{}, wantErr: false, }, } @@ -234,10 +233,12 @@ func TestParseWalletsFile(t *testing.T) { }) } - sortWallets(got) - sortWallets(tt.want) - - require.Equal(t, tt.want, got) + for chainID, wallets := range got { + sortWallets(wallets) + wantWallets := tt.want[chainID] + sortWallets(wantWallets) + require.Equal(t, wantWallets, wallets) + } }) } }