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
12 changes: 12 additions & 0 deletions pkg/keyring/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,15 @@ func GetAddress(kr sdkkeyring.Keyring, name string) (types.AccAddress, error) {
}
return rec.GetAddress()
}

func GetBech32Address(kr sdkkeyring.Keyring, name, hrp string) (string, error) {
rec, err := kr.Key(name)
if err != nil {
return "", err
}
addr, err := rec.GetAddress()
if err != nil {
return "", err
}
return types.Bech32ifyAddressBytes(hrp, addr.Bytes())
}
44 changes: 44 additions & 0 deletions pkg/keyring/keyring_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package keyring

import (
"bytes"
"testing"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
)

func TestGetBech32Address(t *testing.T) {
reg := codectypes.NewInterfaceRegistry()
cryptocodec.RegisterInterfaces(reg)
cdc := codec.NewProtoCodec(reg)
kr := sdkkeyring.NewInMemory(cdc)

rec, _, err := kr.NewMnemonic("test", sdkkeyring.English, DefaultHDPath, DefaultBIP39Passphrase, hd.Secp256k1)
if err != nil {
t.Fatalf("new mnemonic: %v", err)
}
addr, err := rec.GetAddress()
if err != nil {
t.Fatalf("get address: %v", err)
}

got, err := GetBech32Address(kr, "test", "lumera")
if err != nil {
t.Fatalf("get bech32 address: %v", err)
}
if got == "" {
t.Fatal("empty bech32 address")
}
bz, err := sdk.GetFromBech32(got, "lumera")
if err != nil {
t.Fatalf("decode bech32: %v", err)
}
if !bytes.Equal(bz, addr.Bytes()) {
t.Fatalf("decoded address mismatch")
}
}
14 changes: 8 additions & 6 deletions sdk/action/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
actiontypes "github.com/LumeraProtocol/lumera/x/action/v1/types"
"github.com/LumeraProtocol/supernode/v2/pkg/cascadekit"
"github.com/LumeraProtocol/supernode/v2/pkg/codec"
keyringpkg "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
snkeyring "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
"github.com/LumeraProtocol/supernode/v2/pkg/logtrace"
"github.com/LumeraProtocol/supernode/v2/pkg/utils"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
Expand Down Expand Up @@ -68,20 +68,22 @@ type ClientImpl struct {

// Verify interface compliance at compile time
var _ Client = (*ClientImpl)(nil)
var newLumeraAdapter = lumera.NewAdapter

// NewClient creates a new action client
func NewClient(ctx context.Context, config config.Config, logger log.Logger) (Client, error) {
if logger == nil {
logger = log.NewNoopLogger()
}

addr, err := keyringpkg.GetAddress(config.Account.Keyring, config.Account.KeyName)
// Enforce Lumera HRP for secure transport identity, independent of global SDK config.
addr, err := snkeyring.GetBech32Address(config.Account.Keyring, config.Account.KeyName, snkeyring.AccountAddressPrefix)
if err != nil {
return nil, fmt.Errorf("resolve signer address: %w", err)
}

// Create lumera client once
lumeraClient, err := lumera.NewAdapter(ctx,
lumeraClient, err := newLumeraAdapter(ctx,
lumera.ConfigParams{
GRPCAddr: config.Lumera.GRPCAddr,
ChainID: config.Lumera.ChainID,
Expand All @@ -105,7 +107,7 @@ func NewClient(ctx context.Context, config config.Config, logger log.Logger) (Cl
logger: logger,
keyring: config.Account.Keyring,
lumeraClient: lumeraClient,
signerAddr: addr.String(),
signerAddr: addr,
}, nil
}

Expand Down Expand Up @@ -361,7 +363,7 @@ func (c *ClientImpl) GenerateStartCascadeSignatureFromFileDeprecated(ctx context
return "", fmt.Errorf("blake3: %w", err)
}
dataHashB64 := base64.StdEncoding.EncodeToString(h)
sig, err := keyringpkg.SignBytes(c.keyring, c.config.Account.KeyName, []byte(dataHashB64))
sig, err := snkeyring.SignBytes(c.keyring, c.config.Account.KeyName, []byte(dataHashB64))
if err != nil {
return "", fmt.Errorf("sign hash string: %w", err)
}
Expand Down Expand Up @@ -441,7 +443,7 @@ func (c *ClientImpl) GenerateDownloadSignature(ctx context.Context, actionID, cr
c.logger.Info(ctx, "Signing download with ICA signer", "signer", signerAddr, "key_name", keyName)
}
// Sign only the actionID using raw bytes so verification can succeed without ADR-36 signer context.
sig, err := keyringpkg.SignBytes(c.keyring, keyName, []byte(actionID))
sig, err := snkeyring.SignBytes(c.keyring, keyName, []byte(actionID))
if err != nil {
return "", fmt.Errorf("sign download payload: %w", err)
}
Expand Down
71 changes: 71 additions & 0 deletions sdk/action/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package action

import (
"context"
"testing"

snkeyring "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
sdkconfig "github.com/LumeraProtocol/supernode/v2/sdk/config"
"github.com/LumeraProtocol/supernode/v2/sdk/log"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/LumeraProtocol/supernode/v2/sdk/adapters/lumera"
)

func TestNewClientUsesLumeraBech32(t *testing.T) {
kr := newTestKeyring(t)
rec, _, err := kr.NewMnemonic("test", sdkkeyring.English, snkeyring.DefaultHDPath, snkeyring.DefaultBIP39Passphrase, hd.Secp256k1)
if err != nil {
t.Fatalf("new mnemonic: %v", err)
}
addr, err := rec.GetAddress()
if err != nil {
t.Fatalf("get address: %v", err)
}
lumeraAddr, err := sdk.Bech32ifyAddressBytes(snkeyring.AccountAddressPrefix, addr.Bytes())
if err != nil {
t.Fatalf("bech32ify lumera: %v", err)
}
cosmosAddr, err := sdk.Bech32ifyAddressBytes("cosmos", addr.Bytes())
if err != nil {
t.Fatalf("bech32ify cosmos: %v", err)
}

origAdapter := newLumeraAdapter
defer func() { newLumeraAdapter = origAdapter }()
newLumeraAdapter = func(ctx context.Context, cfg lumera.ConfigParams, logger log.Logger) (lumera.Client, error) {
return nil, nil
}

cfg := sdkconfig.Config{
Account: sdkconfig.AccountConfig{KeyName: "test", Keyring: kr},
Lumera: sdkconfig.LumeraConfig{GRPCAddr: "127.0.0.1:1", ChainID: "lumera-test"},
}
client, err := NewClient(context.Background(), cfg, log.NewNoopLogger())
if err != nil {
t.Fatalf("new client: %v", err)
}
impl, ok := client.(*ClientImpl)
if !ok {
t.Fatalf("expected *ClientImpl, got %T", client)
}
if impl.signerAddr != lumeraAddr {
t.Fatalf("signer address mismatch: got %s want %s", impl.signerAddr, lumeraAddr)
}
if impl.signerAddr == cosmosAddr {
t.Fatalf("signer address not normalized: got %s", impl.signerAddr)
}
}

func newTestKeyring(t *testing.T) sdkkeyring.Keyring {
t.Helper()
reg := codectypes.NewInterfaceRegistry()
cryptocodec.RegisterInterfaces(reg)
cdc := codec.NewProtoCodec(reg)
return sdkkeyring.NewInMemory(cdc)
}
7 changes: 4 additions & 3 deletions sdk/net/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/LumeraProtocol/supernode/v2/sdk/adapters/lumera"
"github.com/LumeraProtocol/supernode/v2/sdk/log"

keyringpkg "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
snkeyring "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)

Expand All @@ -35,7 +35,8 @@ func NewClientFactory(ctx context.Context, logger log.Logger, keyring keyring.Ke
logger = log.NewNoopLogger()
}

addr, err := keyringpkg.GetAddress(keyring, config.KeyName)
// Enforce Lumera HRP for secure transport identity, independent of global SDK config.
addr, err := snkeyring.GetBech32Address(keyring, config.KeyName, snkeyring.AccountAddressPrefix)
if err != nil {
logger.Error(ctx, "failed to resolve signer address from keyring",
map[string]interface{}{"key_name": config.KeyName, "error": err.Error()},
Expand All @@ -60,7 +61,7 @@ func NewClientFactory(ctx context.Context, logger log.Logger, keyring keyring.Ke
clientOptions: opts,
config: config,
lumeraClient: lumeraClient,
signerAddr: addr.String(),
signerAddr: addr,
}, nil
}

Expand Down
88 changes: 88 additions & 0 deletions sdk/net/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package net

import (
"context"
"testing"

snkeyring "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/hd"
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
)

func newTestKeyring(t *testing.T) sdkkeyring.Keyring {
t.Helper()
reg := codectypes.NewInterfaceRegistry()
cryptocodec.RegisterInterfaces(reg)
cdc := codec.NewProtoCodec(reg)
return sdkkeyring.NewInMemory(cdc)
}

func TestNewClientFactoryUsesLumeraBech32(t *testing.T) {
kr := newTestKeyring(t)
rec, _, err := kr.NewMnemonic("test", sdkkeyring.English, snkeyring.DefaultHDPath, snkeyring.DefaultBIP39Passphrase, hd.Secp256k1)
if err != nil {
t.Fatalf("new mnemonic: %v", err)
}
addr, err := rec.GetAddress()
if err != nil {
t.Fatalf("get address: %v", err)
}
expected, err := sdk.Bech32ifyAddressBytes(snkeyring.AccountAddressPrefix, addr.Bytes())
if err != nil {
t.Fatalf("bech32ify: %v", err)
}

factory, err := NewClientFactory(context.Background(), nil, kr, nil, FactoryConfig{KeyName: "test"})
if err != nil {
t.Fatalf("new client factory: %v", err)
}
if factory == nil {
t.Fatal("expected factory")
}
if factory.signerAddr != expected {
t.Fatalf("signer address mismatch: got %s want %s", factory.signerAddr, expected)
}
}

func TestNewClientFactoryNormalizesNonLumeraPrefix(t *testing.T) {
kr := newTestKeyring(t)
rec, _, err := kr.NewMnemonic("test", sdkkeyring.English, snkeyring.DefaultHDPath, snkeyring.DefaultBIP39Passphrase, hd.Secp256k1)
if err != nil {
t.Fatalf("new mnemonic: %v", err)
}
addr, err := rec.GetAddress()
if err != nil {
t.Fatalf("get address: %v", err)
}
cosmosAddr, err := sdk.Bech32ifyAddressBytes("cosmos", addr.Bytes())
if err != nil {
t.Fatalf("bech32ify cosmos: %v", err)
}
expected, err := sdk.Bech32ifyAddressBytes(snkeyring.AccountAddressPrefix, addr.Bytes())
if err != nil {
t.Fatalf("bech32ify lumera: %v", err)
}

factory, err := NewClientFactory(context.Background(), nil, kr, nil, FactoryConfig{KeyName: "test"})
if err != nil {
t.Fatalf("new client factory: %v", err)
}
if factory.signerAddr == cosmosAddr {
t.Fatalf("signer address was not normalized: got %s", factory.signerAddr)
}
if factory.signerAddr != expected {
t.Fatalf("signer address mismatch: got %s want %s", factory.signerAddr, expected)
}
}

func TestNewClientFactoryMissingKey(t *testing.T) {
kr := newTestKeyring(t)
_, err := NewClientFactory(context.Background(), nil, kr, nil, FactoryConfig{KeyName: "missing"})
if err == nil {
t.Fatal("expected error")
}
}
12 changes: 7 additions & 5 deletions sdk/net/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/LumeraProtocol/supernode/v2/sdk/log"

pb "github.com/LumeraProtocol/supernode/v2/gen/supernode"
keyringpkg "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
snkeyring "github.com/LumeraProtocol/supernode/v2/pkg/keyring"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"google.golang.org/grpc"
"google.golang.org/grpc/health/grpc_health_v1"
Expand All @@ -33,6 +33,7 @@ var _ SupernodeClient = (*supernodeClient)(nil)

// ensure ALTS protocols are registered once per process
var registerALTSOnce sync.Once
var newClientCreds = ltc.NewClientCreds

// NewSupernodeClient creates a new supernode client
func NewSupernodeClient(ctx context.Context, logger log.Logger, keyring keyring.Keyring,
Expand All @@ -55,16 +56,17 @@ func NewSupernodeClient(ctx context.Context, logger log.Logger, keyring keyring.
factoryConfig.PeerType = securekeyx.Simplenode
}

addr, err := keyringpkg.GetAddress(keyring, factoryConfig.KeyName)
// Enforce Lumera HRP for secure transport identity, independent of global SDK config.
addr, err := snkeyring.GetBech32Address(keyring, factoryConfig.KeyName, snkeyring.AccountAddressPrefix)
if err != nil {
return nil, fmt.Errorf("resolve signer address: %w", err)
}

// Create client credentials
clientCreds, err := ltc.NewClientCreds(&ltc.ClientOptions{
clientCreds, err := newClientCreds(&ltc.ClientOptions{
CommonOptions: ltc.CommonOptions{
Keyring: keyring,
LocalIdentity: addr.String(),
LocalIdentity: addr,
PeerType: factoryConfig.PeerType,
Validator: lumeraClient,
},
Expand All @@ -81,7 +83,7 @@ func NewSupernodeClient(ctx context.Context, logger log.Logger, keyring keyring.

logger.Debug(ctx, "Preparing to connect to supernode securely",
"endpoint", targetSupernode.GrpcEndpoint, "target_id", targetSupernode.CosmosAddress,
"local_id", addr.String(), "peer_type", factoryConfig.PeerType)
"local_id", addr, "peer_type", factoryConfig.PeerType)

// Use provided client options or defaults
options := clientOptions
Expand Down
Loading