Skip to content

Commit

Permalink
feat: add wallet service (#1241)
Browse files Browse the repository at this point in the history
  • Loading branch information
ambersun1234 authored Apr 30, 2024
1 parent 2433dac commit 492e5b3
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 146 deletions.
8 changes: 6 additions & 2 deletions node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/pactus-project/pactus/util"
"github.com/pactus-project/pactus/util/logger"
"github.com/pactus-project/pactus/version"
"github.com/pactus-project/pactus/wallet"
"github.com/pactus-project/pactus/www/grpc"
"github.com/pactus-project/pactus/www/http"
"github.com/pactus-project/pactus/www/jsonrpc"
Expand Down Expand Up @@ -46,9 +47,11 @@ func NewNode(genDoc *genesis.Genesis, conf *config.Config,
// Initialize the logger
logger.InitGlobalLogger(conf.Logger)

chainType := genDoc.ChainType()

logger.Info("You are running a Pactus blockchain",
"version", version.NodeVersion,
"network", genDoc.ChainType())
"network", chainType)

messageCh := make(chan message.Message, 500)
eventCh := make(chan event.Event, 500)
Expand All @@ -74,6 +77,7 @@ func NewNode(genDoc *genesis.Genesis, conf *config.Config,
}

consMgr := consensus.NewManager(conf.Consensus, st, valKeys, rewardAddrs, messageCh)
walletMgr := wallet.NewWalletManager(chainType)

syn, err := sync.NewSynchronizer(conf.Sync, valKeys, st, consMgr, net, messageCh)
if err != nil {
Expand All @@ -84,7 +88,7 @@ func NewNode(genDoc *genesis.Genesis, conf *config.Config,
if conf.GRPC.BasicAuth != "" {
enableHTTPAuth = true
}
grpcServer := grpc.NewServer(conf.GRPC, st, syn, net, consMgr)
grpcServer := grpc.NewServer(conf.GRPC, st, syn, net, consMgr, walletMgr)
httpServer := http.NewServer(conf.HTTP, enableHTTPAuth)
jsonrpcServer := jsonrpc.NewServer(conf.JSONRPC)
nanomsgServer := nanomsg.NewServer(conf.Nanomsg, eventCh)
Expand Down
170 changes: 170 additions & 0 deletions wallet/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package wallet

import (
"github.com/pactus-project/pactus/crypto"
"github.com/pactus-project/pactus/crypto/bls"
"github.com/pactus-project/pactus/genesis"
"github.com/pactus-project/pactus/types/tx"
"github.com/pactus-project/pactus/wallet/vault"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

type Manager struct {
wallets map[string]*Wallet
chainType genesis.ChainType
}

func NewWalletManager(chainType genesis.ChainType) *Manager {
return &Manager{
wallets: make(map[string]*Wallet),
chainType: chainType,
}
}

func (w *Manager) GetValidatorAddress(
publicKey string,
) (string, error) {
pubKey, err := bls.PublicKeyFromString(publicKey)
if err != nil {
return "", err
}

return pubKey.ValidatorAddress().String(), nil
}

func (w *Manager) CreateWallet(
mnemonic, language,
password, walletPath string,
) error {
wlt, err := Create(walletPath, mnemonic, language, w.chainType)
if err != nil {
return err
}

if err := wlt.UpdatePassword("", password); err != nil {
return err
}

if err := wlt.Save(); err != nil {
return err
}

return nil
}

func (w *Manager) LoadWallet(
walletName, walletPath string,
) error {
if _, ok := w.wallets[walletName]; ok {
// TODO: define special codes for errors
return status.Errorf(codes.AlreadyExists, "wallet already loaded")
}

wlt, err := Open(walletPath, true)
if err != nil {
return err
}

w.wallets[walletName] = wlt

return nil
}

func (w *Manager) UnloadWallet(
walletName string,
) error {
if _, ok := w.wallets[walletName]; !ok {
return status.Errorf(codes.NotFound, "wallet is not loaded")
}

delete(w.wallets, walletName)

return nil
}

func (w *Manager) TotalBalance(
walletName string,
) (int64, error) {
wlt, ok := w.wallets[walletName]
if !ok {
return 0, status.Errorf(codes.NotFound, "wallet is not loaded")
}

return wlt.TotalBalance().ToNanoPAC(), nil
}

func (w *Manager) SignRawTransaction(
walletName, password string, rawTx []byte,
) ([]byte, []byte, error) {
wlt, ok := w.wallets[walletName]
if !ok {
return nil, nil, status.Errorf(codes.NotFound, "wallet is not loaded")
}

trx, err := tx.FromBytes(rawTx)
if err != nil {
return nil, nil, err
}

if err := wlt.SignTransaction(password, trx); err != nil {
return nil, nil, err
}

data, err := trx.Bytes()
if err != nil {
return nil, nil, err
}

return trx.ID().Bytes(), data, nil
}

func (w *Manager) GetNewAddress(
walletName, label string,
addressType crypto.AddressType,
) (*vault.AddressInfo, error) {
wlt, ok := w.wallets[walletName]
if !ok {
return nil, status.Errorf(codes.NotFound, "wallet is not loaded")
}

var addressInfo *vault.AddressInfo
switch addressType {
case crypto.AddressTypeBLSAccount:
info, err := wlt.NewBLSAccountAddress(label)
if err != nil {
return nil, err
}
addressInfo = info

case crypto.AddressTypeValidator:
info, err := wlt.NewValidatorAddress(label)
if err != nil {
return nil, err
}
addressInfo = info

case crypto.AddressTypeTreasury:
return nil, status.Errorf(codes.InvalidArgument, "invalid address type")

default:
return nil, status.Errorf(codes.InvalidArgument, "invalid address type")
}

if err := wlt.Save(); err != nil {
return nil, err
}

return addressInfo, nil
}

func (w *Manager) AddressHistory(
walletName, address string,
) ([]HistoryInfo, error) {
wlt, ok := w.wallets[walletName]
if !ok {
return nil, status.Errorf(codes.NotFound, "wallet is not loaded")
}

return wlt.GetHistory(address), nil
}
45 changes: 24 additions & 21 deletions www/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,42 @@ import (
"github.com/pactus-project/pactus/state"
"github.com/pactus-project/pactus/sync"
"github.com/pactus-project/pactus/util/logger"
"github.com/pactus-project/pactus/wallet"
pactus "github.com/pactus-project/pactus/www/grpc/gen/go"
"google.golang.org/grpc"
)

type Server struct {
ctx context.Context
cancel context.CancelFunc
config *Config
listener net.Listener
address string
grpc *grpc.Server
state state.Facade
net network.Network
sync sync.Synchronizer
consMgr consensus.ManagerReader
logger *logger.SubLogger
ctx context.Context
cancel context.CancelFunc
config *Config
listener net.Listener
address string
grpc *grpc.Server
state state.Facade
net network.Network
sync sync.Synchronizer
consMgr consensus.ManagerReader
walletMgr *wallet.Manager
logger *logger.SubLogger
}

func NewServer(conf *Config, st state.Facade, syn sync.Synchronizer,
n network.Network, consMgr consensus.ManagerReader,
walletMgr *wallet.Manager,
) *Server {
ctx, cancel := context.WithCancel(context.Background())

return &Server{
ctx: ctx,
cancel: cancel,
config: conf,
state: st,
sync: syn,
net: n,
consMgr: consMgr,
logger: logger.NewSubLogger("_grpc", nil),
ctx: ctx,
cancel: cancel,
config: conf,
state: st,
sync: syn,
net: n,
consMgr: consMgr,
walletMgr: walletMgr,
logger: logger.NewSubLogger("_grpc", nil),
}
}

Expand Down Expand Up @@ -79,8 +83,7 @@ func (s *Server) startListening(listener net.Listener) error {
pactus.RegisterNetworkServer(grpcServer, networkServer)

if s.config.EnableWallet {
chainType := s.state.Genesis().ChainType()
walletServer := newWalletServer(s, chainType)
walletServer := newWalletServer(s, s.walletMgr)

pactus.RegisterWalletServer(grpcServer, walletServer)
}
Expand Down
6 changes: 5 additions & 1 deletion www/grpc/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ func setup(t *testing.T, conf *Config) *testData {
require.NoError(t, err)
require.NoError(t, defaultWallet.Save())

server := NewServer(conf, mockState, mockSync, mockNet, mockConsMgr)
server := NewServer(
conf, mockState,
mockSync, mockNet,
mockConsMgr, wallet.NewWalletManager(mockState.Genesis().ChainType()),
)
err = server.startListening(listener)
assert.NoError(t, err)

Expand Down
Loading

0 comments on commit 492e5b3

Please sign in to comment.