Skip to content

Commit 2a32985

Browse files
authored
Upgrade Ledger app to v1.3.7 with Nano S+ and Zemu 0.55.3 (#2986)
Update test infrastructure to support newer Ledger hardware and simulator, fixing ledger SDK migration issues in the process.
1 parent f3d46ce commit 2a32985

File tree

7 files changed

+310
-189
lines changed

7 files changed

+310
-189
lines changed

docs/ledger-simulator.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ It uses the `@zondax/zemu` js library to:
88

99
- Download the docker image for the simulator (if needed)
1010
- Set the ledger seed to the default or the user-given one
11-
- Execute the docker container for the simulator by passing to it the avalanche app binary `app_s.elf` (ledger nano s device). That starts the simulated avalanche app.
11+
- Execute the docker container for the simulator by passing to it the avalanche app binary `app_s2.elf` (ledger nano s+ device). That starts the simulated avalanche app.
1212
- Create a rpc entry point to the simulated avalanche app so as the golang client ledger library can connect to the simulator (instead of a real device)
1313
- Previous steps can take some time. Once the app and rpc entry is ready, it prints a custom msg `SIMULATED LEDGER DEV READY` as a means to communicate
1414
with the test code (or the user) that the simulator can start receiving requests (eg connect to it, ask for addresses, etc).
@@ -73,19 +73,19 @@ the simulator, if not, the test is expected to operate agains a real device.
7373

7474
## Ledger device status for avalanche-cli tests interaction
7575

76-
Latest avalanche ledger app downloadable version `v0.7.2` (and also latest ledger live official version `v0.7.0`) can not interact with tests
77-
as it does not support avalanche-cli local network id 1337.
76+
The tests use the Avalanche Ledger app version `v1.3.7`, available as `app_s2.elf` binary (Nano S+ device).
7877

79-
For that, currently the tests operate against a modified version of `v0.7.2`, available as `app_s.elf` binary.
78+
This binary must be built from source from the [ledger-avalanche](https://github.com/ava-labs/ledger-avalanche) repository:
8079

81-
For a real ledger device to be used with the tests, it should be loaded with a supporting version, currently available on dev branch of ledger-avalanche.
82-
83-
It is expected for next downloadable version to:
84-
85-
- support network id 1337
86-
- provide elf binary downloads
80+
```bash
81+
cd /path/to/ledger-avalanche
82+
git checkout v1.3.7
83+
git submodule update --init --recursive
84+
make
85+
cp app/output/app_s2.elf /path/to/avalanche-cli/tests/e2e/ledgerSim/app_s2.elf
86+
```
8787

88-
With that elements provided, CLI e2e could start downloading latest ledger app and using it on CI.
88+
For a real ledger device to be used with the tests, it should be loaded with v1.3.7 or a compatible version.
8989

9090
## How to execute the test script
9191

pkg/keychain/keychain.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,25 @@ func getLedgerIndices(ledgerDevice ledger.Ledger, addressesStr []string) ([]uint
243243
}
244244
// maps the indices of addresses to their corresponding ledger indices
245245
indexMap := map[int]uint32{}
246+
// Build list of indices to query
247+
indicesToQuery := make([]uint32, numLedgerIndicesToSearch)
248+
for i := uint32(0); i < numLedgerIndicesToSearch; i++ {
249+
indicesToQuery[i] = i
250+
}
251+
// Get all public keys at once using PubKeys (which caches GetExtPubKey)
252+
pubKeys, err := ledgerDevice.PubKeys(indicesToQuery)
253+
if err != nil {
254+
return []uint32{}, err
255+
}
246256
// for all ledger indices to search for, find if the ledger address belongs to the input
247257
// addresses and, if so, add the index pair to indexMap, breaking the loop if
248258
// all addresses were found
249-
for ledgerIndex := uint32(0); ledgerIndex < numLedgerIndicesToSearch; ledgerIndex++ {
250-
pubKey, err := ledgerDevice.PubKey(ledgerIndex)
251-
if err != nil {
252-
return []uint32{}, err
253-
}
259+
for ledgerIndex, pubKey := range pubKeys {
254260
ledgerAddress := pubKey.Address()
255261
for addressesIndex, addr := range addresses {
256262
if addr == ledgerAddress {
257263
ux.Logger.PrintToUser(" Found index %d for address %s", ledgerIndex, addressesStr[addressesIndex])
258-
indexMap[addressesIndex] = ledgerIndex
264+
indexMap[addressesIndex] = uint32(ledgerIndex)
259265
}
260266
}
261267
if len(indexMap) == len(addresses) {
@@ -278,13 +284,19 @@ func getLedgerIndices(ledgerDevice ledger.Ledger, addressesStr []string) ([]uint
278284
func searchForFundedLedgerIndices(network models.Network, ledgerDevice ledger.Ledger, amount uint64) ([]uint32, error) {
279285
ux.Logger.PrintToUser("Looking for ledger indices to pay for %.9f AVAX...", float64(amount)/float64(units.Avax))
280286
pClient := platformvm.NewClient(network.Endpoint)
287+
// Build list of indices to query
288+
indicesToQuery := make([]uint32, numLedgerIndicesToSearchForBalance)
289+
for i := uint32(0); i < numLedgerIndicesToSearchForBalance; i++ {
290+
indicesToQuery[i] = i
291+
}
292+
// Get all public keys at once using PubKeys (which caches GetExtPubKey)
293+
pubKeys, err := ledgerDevice.PubKeys(indicesToQuery)
294+
if err != nil {
295+
return []uint32{}, err
296+
}
281297
totalBalance := uint64(0)
282298
ledgerIndices := []uint32{}
283-
for ledgerIndex := uint32(0); ledgerIndex < numLedgerIndicesToSearchForBalance; ledgerIndex++ {
284-
pubKey, err := ledgerDevice.PubKey(ledgerIndex)
285-
if err != nil {
286-
return []uint32{}, err
287-
}
299+
for ledgerIndex, pubKey := range pubKeys {
288300
ledgerAddress := pubKey.Address()
289301
ctx, cancel := utils.GetAPIContext()
290302
resp, err := pClient.GetBalance(ctx, []ids.ShortID{ledgerAddress})
@@ -295,7 +307,7 @@ func searchForFundedLedgerIndices(network models.Network, ledgerDevice ledger.Le
295307
if resp.Balance > 0 {
296308
ux.Logger.PrintToUser(" Found index %d with %.9f AVAX", ledgerIndex, float64(resp.Balance)/float64(units.Avax))
297309
totalBalance += uint64(resp.Balance)
298-
ledgerIndices = append(ledgerIndices, ledgerIndex)
310+
ledgerIndices = append(ledgerIndices, uint32(ledgerIndex))
299311
}
300312
if totalBalance >= amount {
301313
break

tests/e2e/ledgerSim/app_s.elf

-301 KB
Binary file not shown.

tests/e2e/ledgerSim/app_s2.elf

381 KB
Binary file not shown.

tests/e2e/ledgerSim/launchAndApproveTxs.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const rl = createInterface({
88

99
const Resolve = require('path').resolve
1010

11-
const appPath = Resolve('app_s.elf')
11+
const appPath = Resolve('app_s2.elf')
1212
const waitTimeout = 60000;
1313
const waitUntilClose = 1000;
1414
const grpcPort = 3002;
@@ -29,16 +29,17 @@ const options = {
2929
...DEFAULT_START_OPTIONS,
3030
custom: `-s "${appSeed}"`,
3131
startDelay: 300000,
32+
model: "nanosp",
3233
}
3334

3435
async function main() {
35-
const sim = new Zemu(appPath, {}, "127.0.0.1", transportPort, speculosApiPort);
36+
const sim = new Zemu(appPath);
3637

3738
await Zemu.checkAndPullImage();
3839
await Zemu.stopAllEmuContainers();
3940

4041
await sim.start(options)
41-
42+
4243
sim.startGRPCServer("localhost", grpcPort);
4344

4445
await sim.waitForText("Avalanche", waitTimeout, true);

tests/e2e/ledgerSim/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"dependencies": {
3-
"@zondax/zemu": "0.36.0"
3+
"@zondax/zemu": "0.55.3"
44
}
55
}

0 commit comments

Comments
 (0)