mirror of
https://github.com/aljazceru/ark.git
synced 2025-12-18 12:44:19 +01:00
Add admin APIs to manage wallet (#226)
* Add admin rpcs to manage wallet * Fix * Fixes * Add sleeping time * Increase sleeping time
This commit is contained in:
committed by
GitHub
parent
fb8a127f4f
commit
1c67c56d9d
@@ -12,28 +12,13 @@ import (
|
||||
|
||||
type adminHandler struct {
|
||||
adminService application.AdminService
|
||||
aspService application.Service
|
||||
}
|
||||
|
||||
func NewAdminHandler(adminService application.AdminService) arkv1.AdminServiceServer {
|
||||
return &adminHandler{adminService}
|
||||
}
|
||||
|
||||
func (a *adminHandler) GetBalance(ctx context.Context, _ *arkv1.GetBalanceRequest) (*arkv1.GetBalanceResponse, error) {
|
||||
balance, err := a.adminService.GetBalance(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GetBalanceResponse{
|
||||
MainAccount: &arkv1.Balance{
|
||||
Locked: convertSatoshis(balance.MainAccountBalance.Locked),
|
||||
Available: convertSatoshis(balance.MainAccountBalance.Available),
|
||||
},
|
||||
ConnectorsAccount: &arkv1.Balance{
|
||||
Locked: convertSatoshis(balance.ConnectorsAccountBalance.Locked),
|
||||
Available: convertSatoshis(balance.ConnectorsAccountBalance.Available),
|
||||
},
|
||||
}, nil
|
||||
func NewAdminHandler(
|
||||
adminService application.AdminService, aspService application.Service,
|
||||
) arkv1.AdminServiceServer {
|
||||
return &adminHandler{adminService, aspService}
|
||||
}
|
||||
|
||||
func (a *adminHandler) GetRoundDetails(ctx context.Context, req *arkv1.GetRoundDetailsRequest) (*arkv1.GetRoundDetailsResponse, error) {
|
||||
@@ -114,28 +99,6 @@ func (a *adminHandler) GetScheduledSweep(ctx context.Context, _ *arkv1.GetSchedu
|
||||
return &arkv1.GetScheduledSweepResponse{Sweeps: sweeps}, nil
|
||||
}
|
||||
|
||||
func (a *adminHandler) GetWalletAddress(ctx context.Context, _ *arkv1.GetWalletAddressRequest) (*arkv1.GetWalletAddressResponse, error) {
|
||||
addr, err := a.adminService.GetWalletAddress(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GetWalletAddressResponse{Address: addr}, nil
|
||||
}
|
||||
|
||||
func (a *adminHandler) GetWalletStatus(ctx context.Context, _ *arkv1.GetWalletStatusRequest) (*arkv1.GetWalletStatusResponse, error) {
|
||||
status, err := a.adminService.GetWalletStatus(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GetWalletStatusResponse{
|
||||
Initialized: status.IsInitialized,
|
||||
Unlocked: status.IsUnlocked,
|
||||
Synced: status.IsSynced,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// convert sats to string BTC
|
||||
func convertSatoshis(sats uint64) string {
|
||||
btc := float64(sats) * 1e-8
|
||||
|
||||
129
server/internal/interface/grpc/handlers/walletservice.go
Normal file
129
server/internal/interface/grpc/handlers/walletservice.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||
"github.com/ark-network/ark/internal/core/ports"
|
||||
)
|
||||
|
||||
type walletHandler struct {
|
||||
walletService ports.WalletService
|
||||
onUnlock func()
|
||||
}
|
||||
|
||||
func NewWalletHandler(walletService ports.WalletService, onUnlock func()) arkv1.WalletServiceServer {
|
||||
return &walletHandler{walletService, onUnlock}
|
||||
}
|
||||
|
||||
func (a *walletHandler) GenSeed(ctx context.Context, _ *arkv1.GenSeedRequest) (*arkv1.GenSeedResponse, error) {
|
||||
seed, err := a.walletService.GenSeed(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GenSeedResponse{Seed: seed}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) Create(ctx context.Context, req *arkv1.CreateRequest) (*arkv1.CreateResponse, error) {
|
||||
if len(req.GetSeed()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet seed")
|
||||
}
|
||||
if len(req.GetPassword()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet password")
|
||||
}
|
||||
|
||||
if err := a.walletService.Create(
|
||||
ctx, req.GetSeed(), req.GetPassword(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.CreateResponse{}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) Restore(ctx context.Context, req *arkv1.RestoreRequest) (*arkv1.RestoreResponse, error) {
|
||||
if len(req.GetSeed()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet seed")
|
||||
}
|
||||
if len(req.GetPassword()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet password")
|
||||
}
|
||||
|
||||
if err := a.walletService.Restore(
|
||||
ctx, req.GetSeed(), req.GetPassword(),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.RestoreResponse{}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) Unlock(ctx context.Context, req *arkv1.UnlockRequest) (*arkv1.UnlockResponse, error) {
|
||||
if len(req.GetPassword()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet password")
|
||||
}
|
||||
if err := a.walletService.Unlock(ctx, req.GetPassword()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go a.onUnlock()
|
||||
|
||||
return &arkv1.UnlockResponse{}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) Lock(ctx context.Context, req *arkv1.LockRequest) (*arkv1.LockResponse, error) {
|
||||
if len(req.GetPassword()) <= 0 {
|
||||
return nil, fmt.Errorf("missing wallet password")
|
||||
}
|
||||
if err := a.walletService.Lock(ctx, req.GetPassword()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.LockResponse{}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) GetStatus(ctx context.Context, _ *arkv1.GetStatusRequest) (*arkv1.GetStatusResponse, error) {
|
||||
status, err := a.walletService.Status(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GetStatusResponse{
|
||||
Initialized: status.IsInitialized(),
|
||||
Unlocked: status.IsUnlocked(),
|
||||
Synced: status.IsSynced(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) DeriveAddress(ctx context.Context, _ *arkv1.DeriveAddressRequest) (*arkv1.DeriveAddressResponse, error) {
|
||||
addr, err := a.walletService.DeriveAddresses(ctx, 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.DeriveAddressResponse{Address: addr[0]}, nil
|
||||
}
|
||||
|
||||
func (a *walletHandler) GetBalance(ctx context.Context, _ *arkv1.GetBalanceRequest) (*arkv1.GetBalanceResponse, error) {
|
||||
availableMainBalance, lockedMainBalance, err := a.walletService.MainAccountBalance(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
availableConnectorsBalance, lockedConnectorsBalance, err := a.walletService.ConnectorsAccountBalance(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &arkv1.GetBalanceResponse{
|
||||
MainAccount: &arkv1.Balance{
|
||||
Locked: convertSatoshis(lockedMainBalance),
|
||||
Available: convertSatoshis(availableMainBalance),
|
||||
},
|
||||
ConnectorsAccount: &arkv1.Balance{
|
||||
Locked: convertSatoshis(lockedConnectorsBalance),
|
||||
Available: convertSatoshis(availableConnectorsBalance),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
arkv1 "github.com/ark-network/ark/api-spec/protobuf/gen/ark/v1"
|
||||
appconfig "github.com/ark-network/ark/internal/app-config"
|
||||
"github.com/ark-network/ark/internal/core/application"
|
||||
interfaces "github.com/ark-network/ark/internal/interface"
|
||||
"github.com/ark-network/ark/internal/interface/grpc/handlers"
|
||||
"github.com/ark-network/ark/internal/interface/grpc/interceptors"
|
||||
@@ -24,9 +25,10 @@ import (
|
||||
)
|
||||
|
||||
type service struct {
|
||||
config Config
|
||||
appConfig *appconfig.Config
|
||||
server *http.Server
|
||||
config Config
|
||||
appConfig *appconfig.Config
|
||||
server *http.Server
|
||||
grpcServer *grpc.Server
|
||||
}
|
||||
|
||||
func NewService(
|
||||
@@ -39,44 +41,107 @@ func NewService(
|
||||
return nil, fmt.Errorf("invalid app config: %s", err)
|
||||
}
|
||||
|
||||
return &service{svcConfig, appConfig, nil, nil}, nil
|
||||
}
|
||||
|
||||
func (s *service) Start() error {
|
||||
withoutAppSvc := false
|
||||
return s.start(withoutAppSvc)
|
||||
}
|
||||
|
||||
func (s *service) Stop() {
|
||||
withAppSvc := true
|
||||
s.stop(withAppSvc)
|
||||
}
|
||||
|
||||
func (s *service) start(withAppSvc bool) error {
|
||||
if err := s.newServer(withAppSvc); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if withAppSvc {
|
||||
appSvc, _ := s.appConfig.AppService()
|
||||
if err := appSvc.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start app service: %s", err)
|
||||
}
|
||||
log.Info("started app service")
|
||||
}
|
||||
|
||||
if s.config.insecure() {
|
||||
// nolint:all
|
||||
go s.server.ListenAndServe()
|
||||
} else {
|
||||
// nolint:all
|
||||
go s.server.ListenAndServeTLS("", "")
|
||||
}
|
||||
log.Infof("started listening at %s", s.config.address())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) stop(withAppSvc bool) {
|
||||
//nolint:all
|
||||
s.server.Shutdown(context.Background())
|
||||
log.Info("stopped grpc server")
|
||||
if withAppSvc {
|
||||
appSvc, _ := s.appConfig.AppService()
|
||||
if appSvc != nil {
|
||||
appSvc.Stop()
|
||||
log.Info("stopped app service")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) newServer(withAppSvc bool) error {
|
||||
grpcConfig := []grpc.ServerOption{
|
||||
interceptors.UnaryInterceptor(svcConfig.AuthUser, svcConfig.AuthPass),
|
||||
interceptors.UnaryInterceptor(s.config.AuthUser, s.config.AuthPass),
|
||||
interceptors.StreamInterceptor(),
|
||||
}
|
||||
if !svcConfig.NoTLS {
|
||||
return nil, fmt.Errorf("tls termination not supported yet")
|
||||
if !s.config.NoTLS {
|
||||
return fmt.Errorf("tls termination not supported yet")
|
||||
}
|
||||
creds := insecure.NewCredentials()
|
||||
if !svcConfig.insecure() {
|
||||
creds = credentials.NewTLS(svcConfig.tlsConfig())
|
||||
if !s.config.insecure() {
|
||||
creds = credentials.NewTLS(s.config.tlsConfig())
|
||||
}
|
||||
grpcConfig = append(grpcConfig, grpc.Creds(creds))
|
||||
|
||||
// Server grpc.
|
||||
grpcServer := grpc.NewServer(grpcConfig...)
|
||||
|
||||
appHandler := handlers.NewHandler(appConfig.AppService())
|
||||
arkv1.RegisterArkServiceServer(grpcServer, appHandler)
|
||||
var appSvc application.Service
|
||||
if withAppSvc {
|
||||
svc, err := s.appConfig.AppService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appSvc = svc
|
||||
appHandler := handlers.NewHandler(appSvc)
|
||||
arkv1.RegisterArkServiceServer(grpcServer, appHandler)
|
||||
}
|
||||
|
||||
adminHandler := handlers.NewAdminHandler(appConfig.AdminService())
|
||||
adminHandler := handlers.NewAdminHandler(s.appConfig.AdminService(), appSvc)
|
||||
arkv1.RegisterAdminServiceServer(grpcServer, adminHandler)
|
||||
|
||||
walletHandler := handlers.NewWalletHandler(s.appConfig.WalletService(), s.onUnlock)
|
||||
arkv1.RegisterWalletServiceServer(grpcServer, walletHandler)
|
||||
|
||||
healthHandler := handlers.NewHealthHandler()
|
||||
grpchealth.RegisterHealthServer(grpcServer, healthHandler)
|
||||
|
||||
// Creds for grpc gateway reverse proxy.
|
||||
gatewayCreds := insecure.NewCredentials()
|
||||
if !svcConfig.insecure() {
|
||||
if !s.config.insecure() {
|
||||
gatewayCreds = credentials.NewTLS(&tls.Config{
|
||||
InsecureSkipVerify: true, // #nosec
|
||||
})
|
||||
}
|
||||
gatewayOpts := grpc.WithTransportCredentials(gatewayCreds)
|
||||
conn, err := grpc.NewClient(
|
||||
svcConfig.gatewayAddress(), gatewayOpts,
|
||||
s.config.gatewayAddress(), gatewayOpts,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// Reverse proxy grpc-gateway.
|
||||
gwmux := runtime.NewServeMux(
|
||||
@@ -92,15 +157,22 @@ func NewService(
|
||||
}),
|
||||
)
|
||||
ctx := context.Background()
|
||||
if err := arkv1.RegisterArkServiceHandler(
|
||||
ctx, gwmux, conn,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := arkv1.RegisterAdminServiceHandler(
|
||||
ctx, gwmux, conn,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
if err := arkv1.RegisterWalletServiceHandler(
|
||||
ctx, gwmux, conn,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if withAppSvc {
|
||||
if err := arkv1.RegisterArkServiceHandler(
|
||||
ctx, gwmux, conn,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
grpcGateway := http.Handler(gwmux)
|
||||
|
||||
@@ -109,43 +181,27 @@ func NewService(
|
||||
mux.Handle("/", handler)
|
||||
|
||||
httpServerHandler := http.Handler(mux)
|
||||
if svcConfig.insecure() {
|
||||
if s.config.insecure() {
|
||||
httpServerHandler = h2c.NewHandler(httpServerHandler, &http2.Server{})
|
||||
}
|
||||
|
||||
server := &http.Server{
|
||||
Addr: svcConfig.address(),
|
||||
s.server = &http.Server{
|
||||
Addr: s.config.address(),
|
||||
Handler: httpServerHandler,
|
||||
TLSConfig: svcConfig.tlsConfig(),
|
||||
TLSConfig: s.config.tlsConfig(),
|
||||
}
|
||||
|
||||
return &service{svcConfig, appConfig, server}, nil
|
||||
}
|
||||
|
||||
func (s *service) Start() error {
|
||||
if s.config.insecure() {
|
||||
// nolint:all
|
||||
go s.server.ListenAndServe()
|
||||
} else {
|
||||
// nolint:all
|
||||
go s.server.ListenAndServeTLS("", "")
|
||||
}
|
||||
log.Infof("started listening at %s", s.config.address())
|
||||
|
||||
if err := s.appConfig.AppService().Start(); err != nil {
|
||||
return fmt.Errorf("failed to start app service: %s", err)
|
||||
}
|
||||
log.Info("started app service")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Stop() {
|
||||
// nolint:all
|
||||
s.server.Shutdown(context.Background())
|
||||
log.Info("stopped grpc server")
|
||||
s.appConfig.AppService().Stop()
|
||||
log.Info("stopped app service")
|
||||
func (s *service) onUnlock() {
|
||||
withoutAppSvc := false
|
||||
s.stop(withoutAppSvc)
|
||||
|
||||
withAppSvc := true
|
||||
if err := s.start(withAppSvc); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func router(
|
||||
|
||||
Reference in New Issue
Block a user