Skip to content

Commit

Permalink
Add Ledger unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
zivkovicmilos committed Apr 2, 2024
1 parent ac7d5e2 commit a68843b
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tm2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
working-directory: tm2
run: |
export GOPATH=$HOME/go
export GOTEST_FLAGS="-v -p 1 -timeout=20m -coverprofile=coverage.out -covermode=atomic"
export GOTEST_FLAGS="-v -p 1 -timeout=20m -coverprofile=coverage.out -covermode=atomic -tags='ledger_mock'"
make ${{ matrix.args }}
touch coverage.out
- uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion tm2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ GOFMT_FLAGS ?= -w
# flags for `make imports`.
GOIMPORTS_FLAGS ?= $(GOFMT_FLAGS)
# test suite flags.
GOTEST_FLAGS ?= -v -p 1 -timeout=30m
GOTEST_FLAGS ?= -v -p 1 -timeout=30m -tags='ledger_mock'

########################################
# Dev tools
Expand Down
10 changes: 10 additions & 0 deletions tm2/pkg/crypto/keys/client/add_ledger_skipped_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//go:build !ledger_mock
// +build !ledger_mock

package client

import "testing"

func TestAdd_Ledger(t *testing.T) {
t.Skip("Please enable the 'ledger_mock' build tags")
}
170 changes: 170 additions & 0 deletions tm2/pkg/crypto/keys/client/add_ledger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
//go:build ledger_mock
// +build ledger_mock

package client

import (
"context"
"strings"
"testing"
"time"

"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// Make sure to run these tests with the following tag enabled:
// -tags='ledger_mock'
func TestAdd_Ledger(t *testing.T) {
t.Parallel()

t.Run("valid ledger reference added", func(t *testing.T) {
t.Parallel()

var (
kbHome = t.TempDir()
baseOptions = BaseOptions{
InsecurePasswordStdin: true,
Home: kbHome,
}

keyName = "key-name"
)

ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()

io := commands.NewTestIO()
io.SetIn(strings.NewReader("test1234\ntest1234\n"))

// Create the command
cmd := NewRootCmdWithBaseConfig(io, baseOptions)

args := []string{
"add",
"ledger",
"--insecure-password-stdin",
"--home",
kbHome,
keyName,
}

require.NoError(t, cmd.ParseAndRun(ctx, args))

// Check the keybase
kb, err := keys.NewKeyBaseFromDir(kbHome)
require.NoError(t, err)

original, err := kb.GetByName(keyName)
require.NoError(t, err)
require.NotNil(t, original)
})

t.Run("valid ledger reference added, overwrite", func(t *testing.T) {
t.Parallel()

var (
kbHome = t.TempDir()
baseOptions = BaseOptions{
InsecurePasswordStdin: true,
Home: kbHome,
}

keyName = "key-name"
)

ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()

io := commands.NewTestIO()
io.SetIn(strings.NewReader("test1234\ntest1234\n"))

// Create the command
cmd := NewRootCmdWithBaseConfig(io, baseOptions)

args := []string{
"add",
"ledger",
"--insecure-password-stdin",
"--home",
kbHome,
keyName,
}

require.NoError(t, cmd.ParseAndRun(ctx, args))

// Check the keybase
kb, err := keys.NewKeyBaseFromDir(kbHome)
require.NoError(t, err)

original, err := kb.GetByName(keyName)
require.NoError(t, err)
require.NotNil(t, original)

io.SetIn(strings.NewReader("y\ntest1234\ntest1234\n"))

cmd = NewRootCmdWithBaseConfig(io, baseOptions)
require.NoError(t, cmd.ParseAndRun(ctx, args))

newKey, err := kb.GetByName(keyName)
require.NoError(t, err)

// Make sure the different key is generated and overwritten
assert.NotEqual(t, original.GetAddress(), newKey.GetAddress())
})

t.Run("valid ledger reference added, no overwrite permission", func(t *testing.T) {
t.Parallel()

var (
kbHome = t.TempDir()
baseOptions = BaseOptions{
InsecurePasswordStdin: true,
Home: kbHome,
}

keyName = "key-name"
)

ctx, cancelFn := context.WithTimeout(context.Background(), 5*time.Second)
defer cancelFn()

io := commands.NewTestIO()
io.SetIn(strings.NewReader("test1234\ntest1234\n"))

// Create the command
cmd := NewRootCmdWithBaseConfig(io, baseOptions)

args := []string{
"add",
"ledger",
"--insecure-password-stdin",
"--home",
kbHome,
keyName,
}

require.NoError(t, cmd.ParseAndRun(ctx, args))

// Check the keybase
kb, err := keys.NewKeyBaseFromDir(kbHome)
require.NoError(t, err)

original, err := kb.GetByName(keyName)
require.NoError(t, err)
require.NotNil(t, original)

io.SetIn(strings.NewReader("n\ntest1234\ntest1234\n"))

cmd = NewRootCmdWithBaseConfig(io, baseOptions)
require.ErrorIs(t, cmd.ParseAndRun(ctx, args), errOverwriteAborted)

newKey, err := kb.GetByName(keyName)
require.NoError(t, err)

// Make sure the key is not overwritten
assert.Equal(t, original.GetAddress(), newKey.GetAddress())
})
}
19 changes: 19 additions & 0 deletions tm2/pkg/crypto/ledger/discover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//go:build !ledger_mock
// +build !ledger_mock

package ledger

import (
ledger_go "github.com/cosmos/ledger-cosmos-go"
)

// discoverLedger defines a function to be invoked at runtime for discovering
// a connected Ledger device.
var discoverLedger discoverLedgerFn = func() (LedgerSECP256K1, error) {
device, err := ledger_go.FindLedgerCosmosUserApp()
if err != nil {
return nil, err
}

return device, nil
}
69 changes: 69 additions & 0 deletions tm2/pkg/crypto/ledger/discover_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//go:build ledger_mock
// +build ledger_mock

package ledger

import (
btcec "github.com/btcsuite/btcd/btcec/v2"
"github.com/gnolang/gno/tm2/pkg/crypto/secp256k1"
)

// discoverLedger defines a function to be invoked at runtime for discovering
// a connected Ledger device.
var discoverLedger discoverLedgerFn = func() (LedgerSECP256K1, error) {
privateKey := secp256k1.GenPrivKey()

_, pubKeyObject := btcec.PrivKeyFromBytes(privateKey[:])

return &MockLedger{
GetAddressPubKeySECP256K1Fn: func(data []uint32, str string) ([]byte, string, error) {
return pubKeyObject.SerializeCompressed(), privateKey.PubKey().Address().String(), nil
},
}, nil
}

type (
closeDelegate func() error
getPublicKeySECP256K1Delegate func([]uint32) ([]byte, error)
getAddressPubKeySECP256K1Delegate func([]uint32, string) ([]byte, string, error)
signSECP256K1Delegate func([]uint32, []byte, byte) ([]byte, error)
)

type MockLedger struct {
CloseFn closeDelegate
GetPublicKeySECP256K1Fn getPublicKeySECP256K1Delegate
GetAddressPubKeySECP256K1Fn getAddressPubKeySECP256K1Delegate
SignSECP256K1Fn signSECP256K1Delegate
}

func (m *MockLedger) Close() error {
if m.CloseFn != nil {
return m.CloseFn()
}

return nil
}

func (m *MockLedger) GetPublicKeySECP256K1(data []uint32) ([]byte, error) {
if m.GetPublicKeySECP256K1Fn != nil {
return m.GetPublicKeySECP256K1Fn(data)
}

return nil, nil
}

func (m *MockLedger) GetAddressPubKeySECP256K1(data []uint32, str string) ([]byte, string, error) {
if m.GetAddressPubKeySECP256K1Fn != nil {
return m.GetAddressPubKeySECP256K1Fn(data, str)
}

return nil, "", nil
}

func (m *MockLedger) SignSECP256K1(d1 []uint32, d2 []byte, d3 byte) ([]byte, error) {
if m.SignSECP256K1Fn != nil {
return m.SignSECP256K1Fn(d1, d2, d3)
}

return nil, nil
}
12 changes: 0 additions & 12 deletions tm2/pkg/crypto/ledger/ledger_secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"

ledger "github.com/cosmos/ledger-cosmos-go"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/crypto/hd"
Expand Down Expand Up @@ -45,17 +44,6 @@ type (
}
)

// discoverLedger defines a function to be invoked at runtime for discovering
// a connected Ledger device.
var discoverLedger discoverLedgerFn = func() (LedgerSECP256K1, error) {
device, err := ledger.FindLedgerCosmosUserApp()
if err != nil {
return nil, err
}

return device, nil
}

// NewPrivKeyLedgerSecp256k1Unsafe will generate a new key and store the public key for later use.
//
// This function is marked as unsafe as it will retrieve a pubkey without user verification.
Expand Down

0 comments on commit a68843b

Please sign in to comment.