Ori Newman 4658f9d05c
Implement BIP 39 and HD wallet features (#1705)
* Naive bip39 with address reuse

* Avoid address reuse in libkaspawallet

* Add wallet daemon

* Use daemon everywhere

* Add forceOverride

* Make CreateUnsignedTransaction endpoint receive amount in sompis

* Collect close UTXOs

* Filter out non-spendable UTXOs from selectUTXOs

* Use different paths for multisig and non multisig

* Fix tests to use non zero path

* Fix multisig cosigner index detection

* Add comments

* Fix dump_unencrypted_data.go according to bip39 and bip32

* Fix wrong derivation path for multisig on wallet creation

* Remove IsSynced endpoint and add validation if wallet is synced for the relevant endpoints

* Rename server address to daemon address

* Fix capacity for extendedPublicKeys

* Use ReadBytes instead of ReadLine

* Add validation when importing

* Increment before using index value, and use it as is

* Save keys file exactly where needed

* Use %+v printErrorAndExit

* Remove redundant consts

* Rnemae collectCloseUTXOs and collectFarUTXOs

* Move typedefs around

* Add comment to addressesToQuery

* Update collectUTXOsFromRecentAddresses comment about locks

* Split collectUTXOs to small functions

* Add sanity check

* Add addEntryToUTXOSet function

* Change validateIsSynced to isSynced

* Simplify createKeyPairsFromFunction logic

* Rename .Sync() to .Save()

* Fix typo

* Create bip39BitSize const

* Add consts to purposes

* Add multisig check for 'send'

* Rename updatedPSTxBytes to partiallySignedTransaction

* Change collectUTXOsFromFarAddresses's comment

* Use setters for last used indexes

* Don't use the pstx acronym

* Fix SetPath

* Remove spaces when reading lines

* Fix walletserver to daemonaddress

* Fix isUTXOSpendable to use DAA score

Co-authored-by: Svarog <feanorr@gmail.com>
2021-05-19 10:03:23 +03:00

106 lines
2.6 KiB
Go

package server
import (
"fmt"
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
"github.com/kaspanet/kaspad/cmd/kaspawallet/keys"
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
"github.com/kaspanet/kaspad/domain/dagconfig"
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
"github.com/kaspanet/kaspad/infrastructure/os/signal"
"github.com/kaspanet/kaspad/util/panics"
"github.com/pkg/errors"
"net"
"os"
"sync"
"time"
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedKaspawalletdServer
rpcClient *rpcclient.RPCClient
params *dagconfig.Params
lock sync.RWMutex
utxos map[externalapi.DomainOutpoint]*walletUTXO
nextSyncStartIndex uint32
keysFile *keys.File
shutdown chan struct{}
}
// Start starts the kaspawalletd server
func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath string) error {
defer panics.HandlePanic(log, "MAIN", nil)
interrupt := signal.InterruptListener()
listener, err := net.Listen("tcp", listen)
if err != nil {
return (errors.Wrapf(err, "Error listening to tcp at %s", listen))
}
rpcClient, err := connectToRPC(params, rpcServer)
if err != nil {
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
}
keysFile, err := keys.ReadKeysFile(params, keysFilePath)
if err != nil {
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
}
serverInstance := &server{
rpcClient: rpcClient,
params: params,
utxos: make(map[externalapi.DomainOutpoint]*walletUTXO),
nextSyncStartIndex: 0,
keysFile: keysFile,
shutdown: make(chan struct{}),
}
spawn("serverInstance.sync", func() {
err := serverInstance.sync()
if err != nil {
printErrorAndExit(errors.Wrap(err, "error syncing the wallet"))
}
})
grpcServer := grpc.NewServer()
pb.RegisterKaspawalletdServer(grpcServer, serverInstance)
spawn("grpcServer.Serve", func() {
err := grpcServer.Serve(listener)
if err != nil {
printErrorAndExit(errors.Wrap(err, "Error serving gRPC"))
}
})
select {
case <-serverInstance.shutdown:
case <-interrupt:
const stopTimeout = 2 * time.Second
stopChan := make(chan interface{})
spawn("gRPCServer.Stop", func() {
grpcServer.GracefulStop()
close(stopChan)
})
select {
case <-stopChan:
case <-time.After(stopTimeout):
log.Warnf("Could not gracefully stop: timed out after %s", stopTimeout)
grpcServer.Stop()
}
}
return nil
}
func printErrorAndExit(err error) {
fmt.Fprintf(os.Stderr, "%+v\n", err)
os.Exit(1)
}