Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: In gnoNativeService, support using the remote Gnokey Mobile service #163

Merged
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
13 changes: 13 additions & 0 deletions expo/android/src/main/java/land/gno/gnonative/GnonativeModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,19 @@ class GnonativeModule : Module() {
}
}

AsyncFunction("startGnokeyMobileService") { promise: Promise ->
try {
bridgeGnoNative?.let {
bridgeGnoNative!!.startGnokeyMobileService()
promise.resolve(true)
} ?: run {
throw GoBridgeNotStartedError()
}
} catch (err: CodedException) {
promise.reject(err)
}
}

AsyncFunction("invokeGrpcMethod") { method: String, jsonMessage: String, promise: Promise ->
try {
bridgeGnoNative?.let {
Expand Down
12 changes: 12 additions & 0 deletions expo/ios/GnonativeModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,18 @@ public class GnonativeModule: Module {
}
}

AsyncFunction("startGnokeyMobileService") { (promise: Promise) in
do {
guard let service = self.bridge else {
throw GnoError(.notStarted)
}
try service.startGnokeyMobileService()
promise.resolve(true)
} catch let error {
promise.reject(error)
}
}

AsyncFunction("closeBridge") { (promise: Promise) in
do {
guard let service = self.bridge else {
Expand Down
5 changes: 5 additions & 0 deletions expo/src/GoBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface GoBridgeInterface {
initBridge(): Promise<void>;
closeBridge(): Promise<void>;
getTcpPort(): Promise<number>;
startGnokeyMobileService(): Promise<void>;
invokeGrpcMethod(method: string, jsonMessage: string): Promise<string>;
createStreamClient(method: string, jsonMessage: string): Promise<string>;
streamClientReceive(id: string): Promise<string>;
Expand All @@ -23,6 +24,10 @@ class GoBridge implements GoBridgeInterface {
return GnonativeModule.getTcpPort();
}

startGnokeyMobileService(): Promise<void> {
return GnonativeModule.startGnokeyMobileService();
}

invokeGrpcMethod(method: string, jsonMessage: string): Promise<string> {
return GnonativeModule.invokeGrpcMethod(method, jsonMessage);
}
Expand Down
7 changes: 7 additions & 0 deletions expo/src/api/GnoNativeApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export class GnoNativeApi implements GnoKeyApi, GoBridgeInterface {
new SetChainIDRequest({ chainId: this.config.chain_id }),
);
console.log('✅ GnoNative bridge initialized.');
if (this.config.start_gnokey_mobile_service) {
await this.startGnokeyMobileService();
console.log('✅ Gnokey Mobile service started.');
}
return true;
} catch (error) {
console.error(error);
Expand Down Expand Up @@ -380,6 +384,9 @@ export class GnoNativeApi implements GnoKeyApi, GoBridgeInterface {
getTcpPort(): Promise<number> {
return GoBridge.getTcpPort();
}
startGnokeyMobileService(): Promise<void> {
return GoBridge.startGnokeyMobileService();
}
invokeGrpcMethod(method: string, jsonMessage: string): Promise<string> {
return GoBridge.invokeGrpcMethod(method, jsonMessage);
}
Expand Down
2 changes: 2 additions & 0 deletions expo/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export enum BridgeStatus {
export interface Config {
remote: string;
chain_id: string;
// If true, initBridge also starts a Gnokey Mobile service. (Only needed for the Gnokey Mobile app.)
start_gnokey_mobile_service: boolean;
}

export interface GnoKeyApi {
Expand Down
32 changes: 32 additions & 0 deletions framework/service/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/peterbourgon/unixtransport"
"go.uber.org/multierr"

gnokey_mobile_service "github.com/gnolang/gnokey-mobile/service"
api_gen "github.com/gnolang/gnonative/api/gen/go"
"github.com/gnolang/gnonative/api/gen/go/_goconnect"
"github.com/gnolang/gnonative/service"
Expand All @@ -23,6 +24,7 @@ type BridgeConfig struct {
TmpDir string
UseTcpListener bool
DisableUdsListener bool
UseGnokeyMobile bool
}

func NewBridgeConfig() *BridgeConfig {
Expand All @@ -38,6 +40,8 @@ type Bridge struct {

serviceServer service.GnoNativeService

gnokeyMobileService gnokey_mobile_service.GnokeyMobileService

ServiceClient
}

Expand Down Expand Up @@ -77,6 +81,10 @@ func NewBridge(config *BridgeConfig) (*Bridge, error) {
svcOpts = append(svcOpts, service.WithDisableUdsListener())
}

if config.UseGnokeyMobile {
svcOpts = append(svcOpts, service.WithUseGnokeyMobile())
}

serviceServer, err := service.NewGnoNativeService(svcOpts...)
if err != nil {
return nil, errors.Wrap(err, "unable to create bridge service")
Expand Down Expand Up @@ -152,6 +160,28 @@ func (b *Bridge) GetTcpAddr() string {
return b.serviceServer.GetTcpAddr()
}

// Start the Gnokey Mobile service and save it in gnokeyMobileService. This will be closed in Close().
// If the gnonative serviceServer is not started, do nothing.
// If gnokeyMobileService is already started, do nothing.
func (b *Bridge) StartGnokeyMobileService() error {
if b.serviceServer == nil {
return nil
}
if b.gnokeyMobileService != nil {
// Already started
return nil
}

// Use the default options
gnokeyMobileService, err := gnokey_mobile_service.NewGnokeyMobileService(b.serviceServer)
if err != nil {
return err
}

b.gnokeyMobileService = gnokeyMobileService
return nil
}

func (b *Bridge) Close() error {
var errs error

Expand All @@ -177,6 +207,8 @@ func (b *Bridge) Close() error {
errs = multierr.Append(errs, err)
}

// TODO: Close b.gnokeyMobileService

cancel()
}

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
connectrpc.com/grpchealth v1.3.0
connectrpc.com/grpcreflect v1.2.0
github.com/gnolang/gno v0.1.1
github.com/gnolang/gnokey-mobile v0.0.0-20240814140149-eb333b936c7c
github.com/oklog/run v1.1.0
github.com/peterbourgon/ff/v3 v3.4.0
github.com/peterbourgon/unixtransport v0.0.3
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gnolang/gnokey-mobile v0.0.0-20240814140149-eb333b936c7c h1:rL7dVjWOpdQxmbsh69HrgAklolhydTZmPvgo6BpgdhE=
github.com/gnolang/gnokey-mobile v0.0.0-20240814140149-eb333b936c7c/go.mod h1:2NrHp15t6QXGNDruOpw6/xN6z50kquVvZs6uxvUNhsQ=
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 h1:GKvsK3oLWG9B1GL7WP/VqwM6C92j5tIvB844oggL9Lk=
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216/go.mod h1:xJhtEL7ahjM1WJipt89gel8tHzfIl/LyMY+lCYh38d8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down
91 changes: 87 additions & 4 deletions service/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ func (s *gnoNativeService) SetRemote(ctx context.Context, req *connect.Request[a
}

func (s *gnoNativeService) GetRemote(ctx context.Context, req *connect.Request[api_gen.GetRemoteRequest]) (*connect.Response[api_gen.GetRemoteResponse], error) {
if s.useGnokeyMobile {
// Always get the remote from the Gnokey Mobile service
res, err := s.gnokeyMobileClient.GetRemote(context.Background(), req)
if err != nil {
return nil, err
}

return connect.NewResponse(res.Msg), nil
}

return connect.NewResponse(&api_gen.GetRemoteResponse{Remote: s.ClientGetRemote()}), nil
}

Expand Down Expand Up @@ -77,6 +87,16 @@ func ConvertKeyInfo(key crypto_keys.Info) (*api_gen.KeyInfo, error) {
func (s *gnoNativeService) ListKeyInfo(ctx context.Context, req *connect.Request[api_gen.ListKeyInfoRequest]) (*connect.Response[api_gen.ListKeyInfoResponse], error) {
s.logger.Debug("ListKeyInfo called")

if s.useGnokeyMobile {
// Always get the list of keys from the Gnokey Mobile service
res, err := s.gnokeyMobileClient.ListKeyInfo(context.Background(), req)
if err != nil {
return nil, err
}

return connect.NewResponse(res.Msg), nil
}

keys, err := s.ClientListKeyInfo()
if err != nil {
return nil, err
Expand Down Expand Up @@ -272,8 +292,12 @@ func (s *gnoNativeService) GetActiveAccount(ctx context.Context, req *connect.Re
func (s *gnoNativeService) QueryAccount(ctx context.Context, req *connect.Request[api_gen.QueryAccountRequest]) (*connect.Response[api_gen.QueryAccountResponse], error) {
s.logger.Debug("QueryAccount", zap.ByteString("address", req.Msg.Address))

c, err := s.getClient()
if err != nil {
return nil, getGrpcError(err)
}
// gnoclient wants the bech32 address.
account, _, err := s.client.QueryAccount(crypto.AddressFromBytes(req.Msg.Address))
account, _, err := c.QueryAccount(crypto.AddressFromBytes(req.Msg.Address))
if err != nil {
return nil, getGrpcError(err)
}
Expand Down Expand Up @@ -324,7 +348,11 @@ func (s *gnoNativeService) Query(ctx context.Context, req *connect.Request[api_g
Data: req.Msg.Data,
}

bres, err := s.client.Query(cfg)
c, err := s.getClient()
if err != nil {
return nil, getGrpcError(err)
}
bres, err := c.Query(cfg)
if err != nil {
return nil, getGrpcError(err)
}
Expand All @@ -335,7 +363,11 @@ func (s *gnoNativeService) Query(ctx context.Context, req *connect.Request[api_g
func (s *gnoNativeService) Render(ctx context.Context, req *connect.Request[api_gen.RenderRequest]) (*connect.Response[api_gen.RenderResponse], error) {
s.logger.Debug("Render", zap.String("packagePath", req.Msg.PackagePath), zap.String("args", req.Msg.Args))

result, _, err := s.client.Render(req.Msg.PackagePath, req.Msg.Args)
c, err := s.getClient()
if err != nil {
return nil, getGrpcError(err)
}
result, _, err := c.Render(req.Msg.PackagePath, req.Msg.Args)
if err != nil {
return nil, getGrpcError(err)
}
Expand All @@ -346,7 +378,11 @@ func (s *gnoNativeService) Render(ctx context.Context, req *connect.Request[api_
func (s *gnoNativeService) QEval(ctx context.Context, req *connect.Request[api_gen.QEvalRequest]) (*connect.Response[api_gen.QEvalResponse], error) {
s.logger.Debug("QEval", zap.String("packagePath", req.Msg.PackagePath), zap.String("expression", req.Msg.Expression))

result, _, err := s.client.QEval(req.Msg.PackagePath, req.Msg.Expression)
c, err := s.getClient()
if err != nil {
return nil, getGrpcError(err)
}
result, _, err := c.QEval(req.Msg.PackagePath, req.Msg.Expression)
if err != nil {
return nil, getGrpcError(err)
}
Expand All @@ -361,6 +397,53 @@ func (s *gnoNativeService) Call(ctx context.Context, req *connect.Request[api_ge

cfg, msgs := convertCallRequest(req.Msg)

if s.useGnokeyMobile {
c, err := s.getClient()
if err != nil {
return getGrpcError(err)
}
tx, err := c.MakeCallTx(*cfg, msgs...)
if err != nil {
return err
}
txJSON, err := amino.MarshalJSON(tx)
if err != nil {
return err
}

// Use Gnokey Mobile to sign.
// Note that req.Msg.CallerAddress must be set to the desired signer. The app can get the
// address using ListKeyInfo.
signedTxJSON, err := s.gnokeyMobileClient.SignTx(
context.Background(),
connect.NewRequest(&api_gen.SignTxRequest{
TxJson: string(txJSON),
}),
)
if err != nil {
return err
}
signedTx := &std.Tx{}
if err := amino.UnmarshalJSON([]byte(signedTxJSON.Msg.SignedTxJson), signedTx); err != nil {
return err
}

// Now broadcast
bres, err := c.BroadcastTxCommit(signedTx)
if err != nil {
return getGrpcError(err)
}

if err := stream.Send(&api_gen.CallResponse{
Result: bres.DeliverTx.Data,
}); err != nil {
s.logger.Error("Call stream.Send returned error", zap.Error(err))
return err
}

return nil
}

s.lock.RLock()
if s.activeAccount == nil {
s.lock.RUnlock()
Expand Down
11 changes: 11 additions & 0 deletions service/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Config struct {
UdsPath string
UseTcpListener bool
DisableUdsListener bool
UseGnokeyMobile bool
}

type GnoNativeOption func(cfg *Config) error
Expand Down Expand Up @@ -327,6 +328,16 @@ var WithDisableUdsListener = func() GnoNativeOption {
}
}

// --- Gnokey Mobile options ---

// WithUseGnokeyMobile sets the gRPC service to use Gnokey Mobile for key-based operations.
var WithUseGnokeyMobile = func() GnoNativeOption {
return func(cfg *Config) error {
cfg.UseGnokeyMobile = true
return nil
}
}

// --- Fallback options ---

var defaults = []FallBackOption{
Expand Down
Loading