Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions kurtosis-devnet/pkg/kurtosis/kurtosis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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)
}
}

Expand Down
95 changes: 51 additions & 44 deletions kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"io"
"math/big"
"os/exec"
"strings"
)

Expand All @@ -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
Expand Down Expand Up @@ -111,62 +115,58 @@ 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 {
return nil, fmt.Errorf("failed to read wallet file: %w", err)
}

// 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
Expand All @@ -190,7 +190,7 @@ func parseStateFile(r io.Reader) (*DeployerState, error) {
}

result := &DeployerState{
Deployments: make(DeploymentStateAddresses),
Deployments: make(map[string]DeploymentState),
Addresses: make(DeploymentAddresses),
}

Expand Down Expand Up @@ -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,
}
}
}

Expand Down Expand Up @@ -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
}
83 changes: 42 additions & 41 deletions kurtosis-devnet/pkg/kurtosis/sources/deployer/deployer_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package deployer

import (
"os"
"sort"
"strings"
"testing"
Expand Down Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -138,66 +137,66 @@ 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,
},
{
name: "private key only - should be ignored",
input: `{
"proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531"
"chain1": {
"proposerPrivateKey": "0xe1ec816e9ad0372e458c474a06e1e6d9e7f7985cbf642a5e5fa44be639789531"
}
}`,
want: WalletList{},
want: map[string]WalletList{
"chain1": {},
},
wantErr: false,
},
{
Expand All @@ -209,7 +208,7 @@ func TestParseWalletsFile(t *testing.T) {
{
name: "empty input",
input: `{}`,
want: WalletList{},
want: map[string]WalletList{},
wantErr: false,
},
}
Expand All @@ -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)
}
})
}
}