From 2a1becdd20252ec368d85e62ef74f906d6121d9f Mon Sep 17 00:00:00 2001 From: Reiers Date: Wed, 15 Jul 2026 18:22:56 +0200 Subject: [PATCH] fix(rpc): resolve ID-typed addresses to pubkey addresses in WalletHas/WalletSign/WalletSignMessage Wallets store keys under the pubkey (BLS / secp / delegated) address, but Filecoin miner data (MinerInfo.Worker, MinerGetBaseInfo.WorkerKey) surfaces the ID-address (f0). A caller that reads MinerGetBaseInfo and then asks the Lantern wallet to sign for the returned WorkerKey would hit 'keystore: key not found' for the ID-address even when the corresponding pubkey key was imported. Lotus quietly resolves the ID -> pubkey inside its wallet path before doing the lookup; we now do the same. Adds resolveToKeyAddress(ctx, addr) which: - passes pubkey-typed addresses through unchanged, - reads the on-chain Account actor via StateAccountKey for ID addresses, - falls back to the original address on resolver error so the caller still sees the underlying keystore error verbatim (fail-soft). WalletHas, WalletSign, and WalletSignMessage all route through the helper. Fixes the last blocker in Curio's mining loop when Lantern is the node: 'WinPoSt failed to check if we win next round: failed to compute VRF: chain: keystore: key not found'. Live-verified on calibration 2026-07-15: WalletHas(f0137632) now returns true after importing only the pubkey key. --- rpc/handlers/chain_api.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/rpc/handlers/chain_api.go b/rpc/handlers/chain_api.go index e7f04df..0986611 100644 --- a/rpc/handlers/chain_api.go +++ b/rpc/handlers/chain_api.go @@ -1233,7 +1233,31 @@ func (c *ChainAPI) WalletHas(ctx context.Context, a address.Address) (bool, erro if c.Wallet == nil { return false, nil } - return c.Wallet.Has(ctx, a) + resolved := c.resolveToKeyAddress(ctx, a) + return c.Wallet.Has(ctx, resolved) +} + +// resolveToKeyAddress maps an ID-typed address (e.g. f0137632) to its +// BLS/secp pubkey-address by reading the on-chain Account actor, matching +// what lotus does inside its wallet-facing calls. Wallets store keys under +// the pubkey-address, but Filecoin miner data (MinerInfo.Worker, +// MinerGetBaseInfo.WorkerKey) surfaces the ID-address; without this +// resolution WalletSign/WalletHas fail with "key not found" for the very +// address a caller would look up from a MinerInfo response. +// +// If `a` is already a pubkey address, it is returned unchanged. If +// resolution fails, the original address is returned so the caller sees +// the underlying keystore error rather than a resolver error swallowing +// it. +func (c *ChainAPI) resolveToKeyAddress(ctx context.Context, a address.Address) address.Address { + if a.Protocol() != address.ID { + return a + } + resolved, err := c.StateAccountKey(ctx, a, types.EmptyTSK) + if err != nil || resolved == address.Undef { + return a + } + return resolved } func (c *ChainAPI) WalletDelete(ctx context.Context, a address.Address) error { if c.Wallet == nil { @@ -1273,7 +1297,7 @@ func (c *ChainAPI) WalletSign(ctx context.Context, a address.Address, msg []byte if c.Wallet == nil { return nil, errors.New("wallet not initialised") } - return c.Wallet.Sign(ctx, a, msg) + return c.Wallet.Sign(ctx, c.resolveToKeyAddress(ctx, a), msg) } func (c *ChainAPI) WalletSignMessage(ctx context.Context, a address.Address, msg *types.Message) (*types.SignedMessage, error) { if c.Wallet == nil { @@ -1283,7 +1307,7 @@ func (c *ChainAPI) WalletSignMessage(ctx context.Context, a address.Address, msg return nil, errors.New("nil message") } mcid := msg.Cid() - sig, err := c.Wallet.Sign(ctx, a, mcid.Bytes()) + sig, err := c.Wallet.Sign(ctx, c.resolveToKeyAddress(ctx, a), mcid.Bytes()) if err != nil { return nil, fmt.Errorf("sign: %w", err) }