diff --git a/PENDING.md b/PENDING.md index 1866128509..d65d34d8a7 100644 --- a/PENDING.md +++ b/PENDING.md @@ -83,5 +83,7 @@ BUG FIXES * SDK * \#1988 Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988) * \#2105 Fix DB Iterator leak, which may leak a go routine. + * [ledger] \#2064 Fix inability to sign and send transactions via the LCD by + loading a Ledger device at runtime. * Tendermint diff --git a/crypto/ledger.go b/crypto/ledger.go index 9d446202f7..b9aa65b56f 100644 --- a/crypto/ledger.go +++ b/crypto/ledger.go @@ -6,13 +6,16 @@ import ( ledger "github.com/zondax/ledger-goclient" ) -// If ledger support (build tag) has been enabled, automically attempt to load -// and set the ledger device, ledgerDevice, if it has not already been set. +// If ledger support (build tag) has been enabled, which implies a CGO dependency, +// set the discoverLedger function which is responsible for loading the Ledger +// device at runtime or returning an error. func init() { - device, err := ledger.FindLedger() - if err != nil { - ledgerDeviceErr = err - } else { - ledgerDevice = device + discoverLedger = func() (LedgerSECP256K1, error) { + device, err := ledger.FindLedger() + if err != nil { + return nil, err + } + + return device, nil } } diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index 8cb175d4f5..ff05d31bae 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -1,24 +1,27 @@ package crypto import ( - "errors" "fmt" + "github.com/pkg/errors" + secp256k1 "github.com/btcsuite/btcd/btcec" tmcrypto "github.com/tendermint/tendermint/crypto" tmsecp256k1 "github.com/tendermint/tendermint/crypto/secp256k1" ) var ( - ledgerDevice LedgerSECP256K1 - ledgerDeviceErr error - - // ErrMissingLedgerDevice is used to reflect that a ledger device load has - // not been attempted. - ErrMissingLedgerDevice = errors.New("missing ledger device") + // discoverLedger defines a function to be invoked at runtime for discovering + // a connected Ledger device. + discoverLedger discoverLedgerFn ) type ( + // discoverLedgerFn defines a Ledger discovery function that returns a + // connected device or an error upon failure. Its allows a method to avoid CGO + // dependencies when Ledger support is potentially not enabled. + discoverLedgerFn func() (LedgerSECP256K1, error) + // DerivationPath represents a Ledger derivation path. DerivationPath []uint32 @@ -47,18 +50,17 @@ type ( // CONTRACT: The ledger device, ledgerDevice, must be loaded and set prior to // any creation of a PrivKeyLedgerSecp256k1. func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tmcrypto.PrivKey, error) { - if ledgerDevice == nil { - err := ErrMissingLedgerDevice - if ledgerDeviceErr != nil { - err = ledgerDeviceErr - } - - return nil, fmt.Errorf("failed to create PrivKeyLedgerSecp256k1: %v", err) + if discoverLedger == nil { + return nil, errors.New("no Ledger discovery function defined") } - pkl := &PrivKeyLedgerSecp256k1{Path: path, ledger: ledgerDevice} + device, err := discoverLedger() + if err != nil { + return nil, errors.Wrap(err, "failed to create PrivKeyLedgerSecp256k1") + } + + pkl := &PrivKeyLedgerSecp256k1{Path: path, ledger: device} - // cache the pubkey for later use pubKey, err := pkl.getPubKey() if err != nil { return nil, err