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
10 changes: 2 additions & 8 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ jobs:
suite: "\\[Docker\\]"
- os: macos-14
suite: "\\[Public Subnet non SOV\\]"
- os: macos-14
suite: "\\[Key\\]"
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down Expand Up @@ -90,14 +92,6 @@ jobs:
npm install -g ts-node
npm install -g tsx

- name: Install Docker on MacOS
if: ${{ (matrix.os == 'macos-14') && (matrix.suite == '\[Public Subnet non SOV\]') }}
run: |
brew install docker
brew install colima
colima start --vm-type vz
sudo ln -s ~/.colima/default/docker.sock /var/run/docker.sock

- name: Generate SSH token for E2E tests
run: |
mkdir -p ~/.ssh && ssh-keygen -b 2048 -t rsa -f ~/.ssh/runner-avalanche-cli-keypair -q -N ""
Expand Down
97 changes: 76 additions & 21 deletions cmd/keycmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,11 +301,6 @@ func listKeys(*cobra.Command, []string) error {
cchain = false
}
queryLedger := len(ledgerIndices) > 0
if queryLedger {
pchain = true
cchain = false
xchain = false
}
if sdkUtils.Belongs(tokenAddresses, "Native") || sdkUtils.Belongs(tokenAddresses, "native") {
showNativeToken = true
}
Expand All @@ -319,7 +314,7 @@ func listKeys(*cobra.Command, []string) error {
for _, index := range ledgerIndices {
ledgerIndicesU32 = append(ledgerIndicesU32, uint32(index))
}
addrInfos, err = getLedgerIndicesInfo(clients.p, ledgerIndicesU32, networks)
addrInfos, err = getLedgerIndicesInfo(clients, networks, ledgerIndicesU32)
if err != nil {
return err
}
Expand Down Expand Up @@ -423,9 +418,9 @@ func getStoredKeyInfo(
}

func getLedgerIndicesInfo(
pClients map[models.Network]platformvm.Client,
ledgerIndices []uint32,
clients *Clients,
networks []models.Network,
ledgerIndices []uint32,
) ([]addressInfo, error) {
ledgerDevice, err := ledger.New()
if err != nil {
Expand All @@ -441,7 +436,8 @@ func getLedgerIndicesInfo(
addrInfos := []addressInfo{}
for i, index := range ledgerIndices {
addr := pubKeys[i].Address()
ledgerAddrInfos, err := getLedgerIndexInfo(pClients, index, networks, addr)
evmAddr := pubKeys[i].EthAddress()
ledgerAddrInfos, err := getLedgerIndexInfo(clients, networks, index, addr, evmAddr)
if err != nil {
return []addressInfo{}, err
}
Expand All @@ -451,28 +447,87 @@ func getLedgerIndicesInfo(
}

func getLedgerIndexInfo(
pClients map[models.Network]platformvm.Client,
index uint32,
clients *Clients,
networks []models.Network,
index uint32,
addr ids.ShortID,
evmAddr common.Address,
) ([]addressInfo, error) {
addrInfos := []addressInfo{}
for _, network := range networks {
pChainAddr, err := address.Format("P", key.GetHRP(network.ID), addr[:])
if err != nil {
return nil, err
}
addrInfo, err := getPChainAddrInfo(
pClients,
network,
pChainAddr,
"ledger",
fmt.Sprintf("index %d", index),
)
if err != nil {
return nil, err
if _, ok := clients.p[network]; ok {
addrInfo, err := getPChainAddrInfo(
clients.p,
network,
pChainAddr,
"ledger",
fmt.Sprintf("index %d", index),
)
if err != nil {
return nil, err
}
addrInfos = append(addrInfos, addrInfo)
}
if _, ok := clients.x[network]; ok {
xChainAddr, err := address.Format("X", key.GetHRP(network.ID), addr[:])
if err != nil {
return nil, err
}
addrInfo, err := getXChainAddrInfo(
clients.x,
network,
xChainAddr,
"ledger",
fmt.Sprintf("index %d", index),
)
if err != nil {
return nil, err
}
addrInfos = append(addrInfos, addrInfo)
}
if _, ok := clients.c[network]; ok {
addrInfosAux, err := getEvmBasedChainAddrInfo(
"C-Chain",
"AVAX",
clients.c[network],
clients.cEndpoint[network],
network,
evmAddr.Hex(),
"ledger",
fmt.Sprintf("index %d", index),
)
if err != nil {
return nil, err
}
addrInfos = append(addrInfos, addrInfosAux...)
}
if _, ok := clients.evm[network]; ok {
for subnetName := range clients.evm[network] {
addrInfo, err := getEvmBasedChainAddrInfo(
subnetName,
subnetToken,
clients.evm[network][subnetName],
clients.evmEndpoint[network][subnetName],
network,
evmAddr.Hex(),
"ledger",
fmt.Sprintf("index %d", index),
)
if err != nil {
ux.Logger.RedXToUser(
"failure obtaining info for blockchain %s on url %s",
subnetName,
clients.blockchainRPC[network][subnetName],
)
continue
}
addrInfos = append(addrInfos, addrInfo...)
}
}
addrInfos = append(addrInfos, addrInfo)
}
return addrInfos, nil
}
Expand Down
22 changes: 22 additions & 0 deletions tests/e2e/commands/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,28 @@ func ExportKeyToFile(keyName string, outputPath string) (string, error) {
return string(out), err
}

/* #nosec G204 */
func ListLedgerKeys(network string, ledgerIndices []uint, subnets string, chains string) (string, error) {
args := []string{KeyCmd, "list", "--" + network, "--" + constants.SkipUpdateFlag}
for _, idx := range ledgerIndices {
args = append(args, "--ledger", fmt.Sprintf("%d", idx))
}
if subnets != "" {
args = append(args, "--subnets", subnets)
}
if chains != "" {
args = append(args, "--blockchains", chains)
}
cmd := exec.Command(CLIBinary, args...)
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(cmd.String())
fmt.Println(string(out))
utils.PrintStdErr(err)
}
return string(out), err
}

/* #nosec G204 */
func KeyTransferSend(
args []string,
Expand Down
91 changes: 90 additions & 1 deletion tests/e2e/testcases/key/list/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package list

import (
"fmt"
"os"

"github.com/ava-labs/avalanche-cli/tests/e2e/commands"
"github.com/ava-labs/avalanche-cli/tests/e2e/utils"
Expand All @@ -12,7 +13,17 @@ import (
)

const (
keyName = "e2eKey"
keyName = "e2eKey"
ledger1Seed = "ledger1"
ledger2Seed = "ledger2"

// Expected addresses for ledger1 seed (deterministic)
ledger1Index0PChain = "P-custom1jkjatcy2vxfx3st0kft8p0jup6k4ucxugtzhlc"
ledger1Index0XChain = "X-custom1jkjatcy2vxfx3st0kft8p0jup6k4ucxugtzhlc"
ledger1Index0CChain = "0x90f207c2D78E871CFd23071f0545e72233B33767"
ledger1Index1PChain = "P-custom13wzadkyffwlk0a936u5y089dxtw3kx5fyaewc9"
ledger1Index1XChain = "X-custom13wzadkyffwlk0a936u5y089dxtw3kx5fyaewc9"
ledger1Index1CChain = "0x6235F11635BfDe6319E836e487A47D4686c4752E"
)

var _ = ginkgo.Describe("[Key] list", func() {
Expand Down Expand Up @@ -58,4 +69,82 @@ var _ = ginkgo.Describe("[Key] list", func() {
gomega.Expect(output).Should(gomega.MatchRegexp(regex4))
gomega.Expect(output).Should(gomega.ContainSubstring(keyName))
})

ginkgo.It("can list ledger addresses for multiple indices and chains", func() {
gomega.Expect(os.Getenv("LEDGER_SIM")).Should(gomega.Equal("true"), "ledger list test not designed for real ledgers: please set env var LEDGER_SIM to true")

// Start ledger simulator once for all tests
interactionEndCh, ledgerSimEndCh := utils.StartLedgerSim(0, ledger1Seed, false)

// Test 1: List all chains (P-Chain, C-Chain, X-Chain) for multiple indices
output, err := commands.ListLedgerKeys("local", []uint{0, 1}, "p,c,x", "")
gomega.Expect(err).Should(gomega.BeNil())

// Verify output contains expected headers (case-insensitive check)
gomega.Expect(output).Should(gomega.ContainSubstring("KIND"))
gomega.Expect(output).Should(gomega.ContainSubstring("NAME"))
gomega.Expect(output).Should(gomega.ContainSubstring("SUBNET"))
gomega.Expect(output).Should(gomega.ContainSubstring("ADDRESS"))
gomega.Expect(output).Should(gomega.ContainSubstring("TOKEN"))
gomega.Expect(output).Should(gomega.ContainSubstring("BALANCE"))

// Verify ledger indices are shown
gomega.Expect(output).Should(gomega.ContainSubstring("index 0"))
gomega.Expect(output).Should(gomega.ContainSubstring("index 1"))

// Verify all chains are listed
gomega.Expect(output).Should(gomega.ContainSubstring("P-Chain"))
gomega.Expect(output).Should(gomega.ContainSubstring("C-Chain"))
gomega.Expect(output).Should(gomega.ContainSubstring("X-Chain"))

// Verify kind is "ledger"
gomega.Expect(output).Should(gomega.ContainSubstring("ledger"))

// Verify specific addresses for index 0 (deterministic with ledger1 seed)
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0PChain))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0XChain))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0CChain))

// Verify specific addresses for index 1 (deterministic with ledger1 seed)
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index1PChain))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index1XChain))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index1CChain))

// Test 2: List only P-Chain addresses
output, err = commands.ListLedgerKeys("local", []uint{0}, "p", "")
gomega.Expect(err).Should(gomega.BeNil())
gomega.Expect(output).Should(gomega.ContainSubstring("P-Chain"))
gomega.Expect(output).Should(gomega.ContainSubstring("index 0"))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0PChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("C-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("X-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0CChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0XChain))

// Test 3: List only C-Chain addresses
output, err = commands.ListLedgerKeys("local", []uint{0}, "c", "")
gomega.Expect(err).Should(gomega.BeNil())
gomega.Expect(output).Should(gomega.ContainSubstring("C-Chain"))
gomega.Expect(output).Should(gomega.ContainSubstring("index 0"))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0CChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("P-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("X-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0PChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0XChain))

// Test 4: List only X-Chain addresses
output, err = commands.ListLedgerKeys("local", []uint{0}, "x", "")
gomega.Expect(err).Should(gomega.BeNil())
gomega.Expect(output).Should(gomega.ContainSubstring("X-Chain"))
gomega.Expect(output).Should(gomega.ContainSubstring("index 0"))
gomega.Expect(output).Should(gomega.ContainSubstring(ledger1Index0XChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("P-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring("C-Chain"))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0PChain))
gomega.Expect(output).ShouldNot(gomega.ContainSubstring(ledger1Index0CChain))

// Close ledger simulator
close(interactionEndCh)
<-ledgerSimEndCh
})
})
Loading