Commit 9742e404 authored by Yann Hodique's avatar Yann Hodique Committed by GitHub

fix(kurtosis-devnet): accommodate new wallets format (#13622)

parent d590f97d
...@@ -28,6 +28,7 @@ type Chain struct { ...@@ -28,6 +28,7 @@ type Chain struct {
Services EndpointMap `json:"services,omitempty"` Services EndpointMap `json:"services,omitempty"`
Nodes []Node `json:"nodes"` Nodes []Node `json:"nodes"`
Addresses deployer.DeploymentAddresses `json:"addresses,omitempty"` Addresses deployer.DeploymentAddresses `json:"addresses,omitempty"`
Wallets WalletMap `json:"wallets,omitempty"`
} }
type Wallet struct { type Wallet struct {
...@@ -39,9 +40,8 @@ type WalletMap map[string]Wallet ...@@ -39,9 +40,8 @@ type WalletMap map[string]Wallet
// KurtosisEnvironment represents the output of a Kurtosis deployment // KurtosisEnvironment represents the output of a Kurtosis deployment
type KurtosisEnvironment struct { type KurtosisEnvironment struct {
L1 *Chain `json:"l1"` L1 *Chain `json:"l1"`
L2 []*Chain `json:"l2"` L2 []*Chain `json:"l2"`
Wallets WalletMap `json:"wallets"`
} }
// KurtosisDeployer handles deploying packages using Kurtosis // KurtosisDeployer handles deploying packages using Kurtosis
...@@ -164,8 +164,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En ...@@ -164,8 +164,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En
} }
env := &KurtosisEnvironment{ env := &KurtosisEnvironment{
L2: make([]*Chain, 0, len(spec.Chains)), L2: make([]*Chain, 0, len(spec.Chains)),
Wallets: d.getWallets(deployerState.Wallets),
} }
// Find L1 endpoint // Find L1 endpoint
...@@ -178,6 +177,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En ...@@ -178,6 +177,7 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En
} }
if deployerState.State != nil { if deployerState.State != nil {
chain.Addresses = deployerState.State.Addresses chain.Addresses = deployerState.State.Addresses
chain.Wallets = d.getWallets(deployerState.Wallets)
} }
env.L1 = chain env.L1 = chain
} }
...@@ -196,7 +196,10 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En ...@@ -196,7 +196,10 @@ func (d *KurtosisDeployer) getEnvironmentInfo(ctx context.Context, spec *spec.En
// Add contract addresses if available // Add contract addresses if available
if deployerState.State != nil && deployerState.State.Deployments != nil { if deployerState.State != nil && deployerState.State.Deployments != nil {
if addresses, ok := deployerState.State.Deployments[chainSpec.NetworkID]; ok { 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)
} }
} }
......
...@@ -7,7 +7,6 @@ import ( ...@@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"os/exec"
"strings" "strings"
) )
...@@ -25,9 +24,14 @@ type DeploymentAddresses map[string]string ...@@ -25,9 +24,14 @@ type DeploymentAddresses map[string]string
// DeploymentStateAddresses maps chain IDs to their contract addresses // DeploymentStateAddresses maps chain IDs to their contract addresses
type DeploymentStateAddresses map[string]DeploymentAddresses type DeploymentStateAddresses map[string]DeploymentAddresses
type DeploymentState struct {
Addresses DeploymentAddresses `json:"addresses"`
Wallets WalletList `json:"wallets"`
}
type DeployerState struct { type DeployerState struct {
Deployments DeploymentStateAddresses `json:"l2s"` Deployments map[string]DeploymentState `json:"l2s"`
Addresses DeploymentAddresses `json:"superchain"` Addresses DeploymentAddresses `json:"superchain"`
} }
// StateFile represents the structure of the state.json file // StateFile represents the structure of the state.json file
...@@ -111,7 +115,9 @@ func NewDeployer(enclave string, opts ...DeployerOption) *Deployer { ...@@ -111,7 +115,9 @@ func NewDeployer(enclave string, opts ...DeployerOption) *Deployer {
} }
// parseWalletsFile parses a JSON file containing wallet information // 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 // Read all data from reader
data, err := io.ReadAll(r) data, err := io.ReadAll(r)
if err != nil { if err != nil {
...@@ -119,54 +125,48 @@ func parseWalletsFile(r io.Reader) (WalletList, error) { ...@@ -119,54 +125,48 @@ func parseWalletsFile(r io.Reader) (WalletList, error) {
} }
// Unmarshal into a map first // 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 { if err := json.Unmarshal(data, &rawData); err != nil {
return nil, fmt.Errorf("failed to decode wallet file: %w", err) return nil, fmt.Errorf("failed to decode wallet file: %w", err)
} }
// Create a map to store wallets by name for id, chain := range rawData {
walletMap := make(map[string]Wallet) // Create a map to store wallets by name
walletMap := make(map[string]Wallet)
// Process each key-value pair
for key, value := range rawData { // Process each key-value pair
if strings.HasSuffix(key, "Address") { for key, value := range chain {
name := strings.TrimSuffix(key, "Address") if strings.HasSuffix(key, "Address") {
wallet := walletMap[name] name := strings.TrimSuffix(key, "Address")
wallet.Address = value wallet := walletMap[name]
wallet.Name = name wallet.Address = value
walletMap[name] = wallet wallet.Name = name
} else if strings.HasSuffix(key, "PrivateKey") { walletMap[name] = wallet
name := strings.TrimSuffix(key, "PrivateKey") } else if strings.HasSuffix(key, "PrivateKey") {
wallet := walletMap[name] name := strings.TrimSuffix(key, "PrivateKey")
wallet.PrivateKey = value wallet := walletMap[name]
wallet.Name = name wallet.PrivateKey = value
walletMap[name] = wallet wallet.Name = name
walletMap[name] = wallet
}
} }
}
// Convert map to list // Convert map to list
result := make(WalletList, 0, len(walletMap)) wl := make(WalletList, 0, len(walletMap))
for _, wallet := range walletMap { for _, wallet := range walletMap {
// Only include wallets that have at least an address // Only include wallets that have at least an address
if wallet.Address != "" { if wallet.Address != "" {
result = append(result, &wallet) wl = append(wl, &wallet)
}
} }
result[id] = wl
} }
return result, nil 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 // hexToDecimal converts a hex string (with or without 0x prefix) to a decimal string
func hexToDecimal(hex string) (string, error) { func hexToDecimal(hex string) (string, error) {
// Remove 0x prefix if present // Remove 0x prefix if present
...@@ -190,7 +190,7 @@ func parseStateFile(r io.Reader) (*DeployerState, error) { ...@@ -190,7 +190,7 @@ func parseStateFile(r io.Reader) (*DeployerState, error) {
} }
result := &DeployerState{ result := &DeployerState{
Deployments: make(DeploymentStateAddresses), Deployments: make(map[string]DeploymentState),
Addresses: make(DeploymentAddresses), Addresses: make(DeploymentAddresses),
} }
...@@ -225,7 +225,9 @@ func parseStateFile(r io.Reader) (*DeployerState, error) { ...@@ -225,7 +225,9 @@ func parseStateFile(r io.Reader) (*DeployerState, error) {
addresses := mapDeployment(deployment) addresses := mapDeployment(deployment)
if len(addresses) > 0 { 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) { ...@@ -269,12 +271,17 @@ func (d *Deployer) ExtractData(ctx context.Context) (*DeployerData, error) {
return nil, err 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) knownWallets, err := d.getKnownWallets(ctx, fs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
wallets = append(wallets, knownWallets...) return &DeployerData{State: state, Wallets: knownWallets}, nil
return &DeployerData{State: state, Wallets: wallets}, nil
} }
package deployer package deployer
import ( import (
"os"
"sort" "sort"
"strings" "strings"
"testing" "testing"
...@@ -67,7 +66,7 @@ func TestParseStateFile(t *testing.T) { ...@@ -67,7 +66,7 @@ func TestParseStateFile(t *testing.T) {
require.True(t, ok, "Chain %s not found in result", tt.chainID) require.True(t, ok, "Chain %s not found in result", tt.chainID)
for key, expected := range tt.expected { 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) 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) { ...@@ -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) { func TestParseWalletsFile(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
input string input string
want WalletList want map[string]WalletList
wantErr bool wantErr bool
}{ }{
{ {
name: "successful parse", name: "successful parse",
input: `{ input: `{
"proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", "chain1": {
"proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", "proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531",
"batcherPrivateKey": "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", "proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F",
"batcherAddress": "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11" "batcherPrivateKey": "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967",
"batcherAddress": "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11"
}
}`, }`,
want: WalletList{ want: map[string]WalletList{
{ "chain1": {
Name: "proposer", {
Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", Name: "proposer",
PrivateKey: "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531", Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F",
}, PrivateKey: "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531",
{ },
Name: "batcher", {
Address: "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11", Name: "batcher",
PrivateKey: "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967", Address: "0x6bd90c2a1AE00384AD9F4BcD76310F54A9CcdA11",
PrivateKey: "0x557313b816b8fb354340883edf86627b3de680a9f3e15aa1f522cbe6f9c7b967",
},
}, },
}, },
wantErr: false, wantErr: false,
}, },
{ {
name: "address only", name: "address only",
input: `{ input: `{
"proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F" "chain1": {
"proposerAddress": "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F"
}
}`, }`,
want: WalletList{ want: map[string]WalletList{
{ "chain1": {
Name: "proposer", {
Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F", Name: "proposer",
Address: "0xDFfA3C478Be83a91286c04721d2e5DF9A133b93F",
},
}, },
}, },
wantErr: false, wantErr: false,
...@@ -195,9 +190,13 @@ func TestParseWalletsFile(t *testing.T) { ...@@ -195,9 +190,13 @@ func TestParseWalletsFile(t *testing.T) {
{ {
name: "private key only - should be ignored", name: "private key only - should be ignored",
input: `{ input: `{
"proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531" "chain1": {
"proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531"
}
}`, }`,
want: WalletList{}, want: map[string]WalletList{
"chain1": {},
},
wantErr: false, wantErr: false,
}, },
{ {
...@@ -209,7 +208,7 @@ func TestParseWalletsFile(t *testing.T) { ...@@ -209,7 +208,7 @@ func TestParseWalletsFile(t *testing.T) {
{ {
name: "empty input", name: "empty input",
input: `{}`, input: `{}`,
want: WalletList{}, want: map[string]WalletList{},
wantErr: false, wantErr: false,
}, },
} }
...@@ -234,10 +233,12 @@ func TestParseWalletsFile(t *testing.T) { ...@@ -234,10 +233,12 @@ func TestParseWalletsFile(t *testing.T) {
}) })
} }
sortWallets(got) for chainID, wallets := range got {
sortWallets(tt.want) sortWallets(wallets)
wantWallets := tt.want[chainID]
require.Equal(t, tt.want, got) sortWallets(wantWallets)
require.Equal(t, wantWallets, wallets)
}
}) })
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment